Merge lp:~unity-team/unity8/tutorial-redesign into lp:unity8
- tutorial-redesign
- Merge into trunk
Status: | Superseded |
---|---|
Proposed branch: | lp:~unity-team/unity8/tutorial-redesign |
Merge into: | lp:unity8 |
Prerequisite: | lp:~unity-team/unity8/side-stage-redesign |
Diff against target: |
5045 lines (+1824/-1529) 66 files modified
plugins/AccountsService/AccountsService.cpp (+16/-0) plugins/AccountsService/AccountsService.h (+7/-0) plugins/AccountsService/AccountsService.qmltypes (+5/-0) plugins/AccountsService/com.canonical.unity.AccountsService.xml (+5/-0) plugins/ScreenGrabber/screengrabber.cpp (+0/-2) plugins/Ubuntu/Gestures/DirectionalDragArea.cpp (+40/-5) plugins/Ubuntu/Gestures/DirectionalDragArea.h (+8/-0) plugins/Ubuntu/Gestures/DirectionalDragArea_p.h (+2/-0) plugins/Utils/CMakeLists.txt (+1/-1) plugins/Utils/Utils.qmltypes (+2/-2) plugins/Utils/plugin.cpp (+2/-2) plugins/Utils/windowinputfilter.cpp (+14/-16) plugins/Utils/windowinputfilter.h (+11/-11) qml/Components/InputMethod.qml (+4/-1) qml/Greeter/Greeter.qml (+10/-6) qml/Launcher/Launcher.qml (+2/-3) qml/Panel/IndicatorsMenu.qml (+0/-2) qml/Shell.qml (+32/-46) qml/Stages/AbstractStage.qml (+3/-0) qml/Stages/ApplicationWindow.qml (+0/-2) qml/Stages/DesktopStage.qml (+61/-9) qml/Stages/PhoneStage.qml (+12/-6) qml/Stages/StagedFullscreenPolicy.qml (+58/-0) qml/Stages/TabletStage.qml (+18/-5) qml/Stages/WindowResizeArea.qml (+1/-1) qml/Stages/WindowedFullscreenPolicy.qml (+41/-0) qml/Tutorial/Arrow.qml (+0/-56) qml/Tutorial/InactivityTimer.qml (+62/-0) qml/Tutorial/Slider.qml (+0/-123) qml/Tutorial/Tick.qml (+0/-29) qml/Tutorial/Tutorial.qml (+43/-18) qml/Tutorial/TutorialBottom.qml (+0/-104) qml/Tutorial/TutorialBottomFinish.qml (+0/-41) qml/Tutorial/TutorialContent.qml (+250/-80) qml/Tutorial/TutorialLeft.qml (+28/-75) qml/Tutorial/TutorialLeftFinish.qml (+0/-41) qml/Tutorial/TutorialLeftLong.qml (+54/-0) qml/Tutorial/TutorialPage.qml (+66/-190) qml/Tutorial/TutorialRight.qml (+0/-223) qml/Tutorial/TutorialTop.qml (+61/-0) qml/Tutorial/graphics/arrow.svg (+19/-0) tests/autopilot/unity8/shell/emulators.py (+0/-2) tests/autopilot/unity8/shell/tests/test_tutorial.py (+0/-57) tests/autopilot/unity8/tutorial.py (+0/-73) tests/mocks/AccountsService/AccountsService.cpp (+20/-0) tests/mocks/AccountsService/AccountsService.h (+10/-0) tests/mocks/AccountsService/AccountsService.qmltypes (+5/-0) tests/mocks/Unity/Application/ApplicationInfo.cpp (+21/-3) tests/mocks/Unity/Application/ApplicationInfo.h (+6/-2) tests/mocks/Unity/Application/ApplicationManager.cpp (+6/-4) tests/mocks/Unity/Application/MirSurface.cpp (+16/-0) tests/mocks/Unity/Application/MirSurface.h (+5/-3) tests/mocks/Unity/Application/MirSurfaceItem.cpp (+9/-0) tests/mocks/Unity/Application/MirSurfaceItem.h (+1/-0) tests/mocks/Unity/Application/Session.cpp (+26/-1) tests/mocks/Unity/Application/Session.h (+7/-0) tests/mocks/Utils/CMakeLists.txt (+1/-1) tests/mocks/Utils/Utils.qmltypes (+2/-2) tests/mocks/Utils/plugin.cpp (+2/-2) tests/plugins/AccountsService/PropertiesServer.cpp (+1/-0) tests/plugins/AccountsService/client.cpp (+37/-0) tests/qmltests/Components/tst_PhysicalKeysMapper.qml (+3/-3) tests/qmltests/Greeter/tst_Greeter.qml (+7/-1) tests/qmltests/Tutorial/tst_Tutorial.qml (+636/-245) tests/qmltests/tst_Shell.qml (+65/-8) tests/qmltests/tst_ShellWithPin.qml (+0/-22) |
To merge this branch: | bzr merge lp:~unity-team/unity8/tutorial-redesign |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Unity8 CI Bot | continuous-integration | Needs Fixing | |
Albert Astals Cid (community) | Abstain | ||
Michael Zanetti | Pending | ||
PS Jenkins bot | continuous-integration | Pending | |
Review via email: mp+288839@code.launchpad.net |
This proposal supersedes a proposal from 2016-03-10.
This proposal has been superseded by a proposal from 2016-03-15.
Commit message
Redesign the first-boot edge tutorial
Description of the change
Based on new design specs [1], this is whole new tutorial code.
Some of the interesting things going on here:
- New DDA feature "monitorOnly" which lets input events "fall through" (i.e. it doesn't own them) but continues to monitor them. This is how we implement the bottom edge tutorial fading out without having to communicate with the app.
- New AccountsService key to keep track of which particular edges are done, now that they are presented separately. We still use the old key for overall "done" status.
- Renamed WindowKeysFilter to WindowInputFilter. I needed a way to keep track of input inactivity. And since WindowKeysFilter was already injecting itself into the event stream and already kept track of timestamps for us (which usually isn't exposed to Qml), I just modified it a bit. I felt like the new scope should be indicated in the name, so I renamed it.
- I took out some old hacks only needed for the old tutorial.
[1] https:/
== Checklist ==
* Are there any related MPs required for this MP to build/function as expected? Please list.
Yes. A new phablet-tools branch for your desktop [2] and a new upload of dbus-property-
[2] https:/
* Did you perform an exploratory manual test run of your code change and any related functionality?
Yes
* Did you make sure that your branch does not contain spurious tags?
Yes
* If you changed the packaging (debian), did you subscribe the ubuntu-unity team to this MP?
NA
* If you changed the UI, has there been a design review?
Yes. Patricia is on board with this MP. She has another screen coming (long swipe on left), but I'll do that as a separate MP.
Michael Terry (mterry) wrote : Posted in a previous version of this proposal | # |
Michael Terry (mterry) wrote : Posted in a previous version of this proposal | # |
OK, I'm opening this up to review, although the final design review isn't done yet and I need to add a couple more qmltests. But I'd like to get the review train started on its way.
Michael Terry (mterry) wrote : Posted in a previous version of this proposal | # |
OK, added more tests and cleaned up existing ones. Hopefully this is "done-ish" from a technical POV and only design-related changes will happen now (like changes to strings or alignment).
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1977
http://
Executed test runs:
ABORTED: http://
ABORTED: http://
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1978
http://
Executed test runs:
UNSTABLE: http://
FAILURE: http://
UNSTABLE: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Michael Zanetti (mzanetti) wrote : Posted in a previous version of this proposal | # |
Hmm... I've just flashed a device and enabled the edges-intro with phablet-config. I could see the intro for left, top and bottom edges, however, still waiting for the right edge one to appear.
====
As you renamed WindowKeyFilter, please update this comment too
qml/Shell.qml: // dummy shortcut to force creation of GlobalShortcutR
===
- readonly property real dragProgress: spreadRepeater.
+ dragProgress: spreadRepeater.
Given that it's not obvious what the dragProgress is used for, please add a comment in the stages code to indicate it. otherwise it's likely to be removed at some point because noone knows what it does.
===
+ ////
Is there a purpose to this? :)
===
+ sourceSize.height: 1080
+ sourceSize.width: 1916
erm... can you explain the values? Looks wrong to me
Michael Zanetti (mzanetti) wrote : Posted in a previous version of this proposal | # |
Notes for myself:
* test if CPU usage drops if screen locks during animation
* test what happens if plugging external screen while in tutorial
Michael Terry (mterry) wrote : Posted in a previous version of this proposal | # |
OK, I've made some changes. One, I added some more space between tutorial text lines, per design request.
Second, also per design request, I've added unique helper text on the bottom edge tutorial for each supported app. This also means that we show the tutorial for each app rather than once for any of them. Since this meant that the tutorial might not formally "finish" for quite some time, I've optimized the rest of the tutorial to use Loaders. So that we're not loading three unused background images a week after the user unboxes their phone.
As for your comments:
> Hmm... I've just flashed a device and enabled the edges-intro
> with phablet-config. I could see the intro for left, top and
> bottom edges, however, still waiting for the right edge one to appear.
As discussed on IRC, we're guessing this was user error. Unless you've seen it again?
====
> As you renamed WindowKeyFilter, please update this comment too
>
> qml/Shell.qml: // dummy shortcut to force creation of GlobalShortcutR
Done.
===
> - readonly property real dragProgress: spreadRepeater.
> + dragProgress: spreadRepeater.
> Given that it's not obvious what the dragProgress is used for,
> please add a comment in the stages code to indicate it. otherwise
> it's likely to be removed at some point because noone knows what it does.
Done.
===
> + ////
>
> Is there a purpose to this? :)
Ah, that's just a little visual separator I use between the public interface part of the object and the implementation parts. Qml doesn't use headers, and while we seem to use the placement of the QtObject component to separate the portions of code, sometimes an object doesn't warrant a QtObject, so it isn't a universal distinguisher. Plus, I like the extra visual space.
I can take it out if it will be as confusing to you as others. I know Cimi doesn't like that I do that.
===
> + sourceSize.height: 1080
> + sourceSize.width: 1916
>
> erm... can you explain the values? Looks wrong to me
Duh, I swapped height and width. Fixed.
===
> * test if CPU usage drops if screen locks during animation
Please do, but note that there isn't any animation anymore. So I expect no CPU difference.
===
> * test what happens if plugging external screen while in tutorial
Ah yes. Here's what I expect the code to do:
- Any visible tutorials that aren't marked for desktop use will fade out.
- The right edge tutorial will appear (or update itself) with desktop-specific text when you have enough apps open.
- If you finish the right edge tutorial while in desktop mode, the tutorial will be marked complete and you won't see any more coach marks. However, if you don't finish the right edge tutorial before undocking, you will continue to see all the tutorials you haven't seen yet, as normal.
How do you feel about that last behavior? It might be tricky to do something much smarter unless either (A) we know the "native" usageScenario of the device or (B) we stop marking the "whole-
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1979
http://
Executed test runs:
UNSTABLE: http://
FAILURE: http://
UNSTABLE: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1981
http://
Executed test runs:
UNSTABLE: http://
FAILURE: http://
UNSTABLE: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Albert Astals Cid (aacid) wrote : Posted in a previous version of this proposal | # |
Text conflict in tests/plugins/
1 conflicts encountered.
Michael Terry (mterry) wrote : Posted in a previous version of this proposal | # |
Fixed conflicts.
Albert Astals Cid (aacid) : Posted in a previous version of this proposal | # |
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1982
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1982
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1983
http://
Executed test runs:
UNSTABLE: http://
FAILURE: http://
UNSTABLE: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1984
http://
Executed test runs:
UNSTABLE: http://
FAILURE: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1985
http://
Executed test runs:
UNSTABLE: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1986
http://
Executed test runs:
UNSTABLE: http://
FAILURE: http://
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Michael Zanetti (mzanetti) wrote : Posted in a previous version of this proposal | # |
+ i18n.tr("Hover your mouse on the right edge to view your open apps") :
+ i18n.tr("Short or long swipe from the right edge to view your open apps")
I know those have been given by design, but gotta point out some errors:
- In windowed mode, you need to push the mouse against the right edge and even overcome some resistance. Hovering is not enough.
- While at it, we might want to ask back on short swipe one too, but I guess that would be ok to oversimplify it in this case.
========
+ text: d.landscape ? i18n.tr("Swipe from the top right edge to open the notification bar")
+ : i18n.tr("Swipe from the top edge to open the notification bar")
this might needs a windowed mode special case too. We don't want to encourage clicking with a mouse so the indicators can also be revealed by clicking the icons. Although this is not wrong. If you have a touch screen too, you can also swipe then on a desktop.
========
+ text: i18n.tr("Swipe from the left edge to open the launcher")
same as for the right edge. With a mouse, it requires pushing towards the edge. Why not special cased here?
Michael Zanetti (mzanetti) wrote : Posted in a previous version of this proposal | # |
Another question:
I figure it will take ages until completed goes to true. Some people might never open the calculator app which would leave us with the tutorial being enabled forever. What are the implications of that?
Michael Terry (mterry) wrote : Posted in a previous version of this proposal | # |
You mention the wording on the left edge drag needing to be changed for desktop mode -- but we don't show that tutorial on desktop. So I'm guessing we can leave it as is.
And you asked about the tutorial never "completing". This is a small issue. And it's why I revised TutorialContent to use loaders for each tutorial page. I don't think it's a problem, per se. But it does mean that we'll likely have the TutorialBottom page loaded most of the time. Until they load all the bottom-supported apps anyway...
Michael Zanetti (mzanetti) wrote : Posted in a previous version of this proposal | # |
On the right edge in windowed mode, it's not only the text, but the hoverMouseArea disappered and it's not possible to get past that step any more.
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1987
http://
Executed test runs:
UNSTABLE: http://
FAILURE: http://
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Albert Astals Cid (aacid) wrote : Posted in a previous version of this proposal | # |
Text conflict in qml/Launcher/
1 conflicts encountered.
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1987
https:/
Executed test runs:
Click here to trigger a rebuild:
https:/
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1988
https:/
Executed test runs:
Click here to trigger a rebuild:
https:/
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1988
http://
Executed test runs:
UNSTABLE: http://
FAILURE: http://
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1989
https:/
Executed test runs:
Click here to trigger a rebuild:
https:/
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1989
http://
Executed test runs:
UNSTABLE: http://
FAILURE: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1989
https:/
Executed test runs:
Click here to trigger a rebuild:
https:/
Albert Astals Cid (aacid) wrote : Posted in a previous version of this proposal | # |
Text conflict in qml/Stages/
Text conflict in qml/Stages/
2 conflicts encountered.
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1990
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1990
http://
Executed test runs:
UNSTABLE: http://
FAILURE: http://
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1992
https:/
Executed test runs:
SUCCESS: https:/
UNSTABLE: https:/
UNSTABLE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1992
http://
Executed test runs:
UNSTABLE: http://
FAILURE: http://
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1993
https:/
Executed test runs:
SUCCESS: https:/
UNSTABLE: https:/
UNSTABLE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1993
http://
Executed test runs:
UNSTABLE: http://
FAILURE: http://
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1995
https:/
Executed test runs:
SUCCESS: https:/
UNSTABLE: https:/
UNSTABLE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1995
http://
Executed test runs:
UNSTABLE: http://
FAILURE: http://
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1996
https:/
Executed test runs:
UNSTABLE: https:/
UNSTABLE: https:/
UNSTABLE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
Michał Sawicz (saviq) wrote : Posted in a previous version of this proposal | # |
Tests need fixin ↑?
Michael Terry (mterry) wrote : Posted in a previous version of this proposal | # |
Fixed the qmluitest, and removed the autopilot test. The tutorial is harder to test via one autopilot test now that the pages have been split up and separately triggered. Plus, we cover them well in qmluitests. And there's nothing autopilot-centric to test there.
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1999
https:/
Executed test runs:
UNSTABLE: https:/
UNSTABLE: https:/
UNSTABLE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:2000
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
UNSTABLE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:2002
https:/
Executed test runs:
UNSTABLE: https:/
SUCCESS: https:/
UNSTABLE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:2002
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
UNSTABLE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:2004
https:/
Executed test runs:
SUCCESS: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
Unity8 CI Bot (unity8-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:2002
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
Albert Astals Cid (aacid) : | # |
- 2003. By Michael Terry
-
Patch from dednick, fixing my bad merge
Unity8 CI Bot (unity8-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:2003
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
- 2004. By Michael Terry
-
merge from side-stage-redesign
Unity8 CI Bot (unity8-ci-bot) wrote : | # |
FAILED: Continuous integration, rev:2004
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
- 2005. By Michael Terry
-
Merge in shell_chrome
- 2006. By Michael Terry
-
Some test fixes
- 2007. By Michael Terry
-
Fix last failing test
- 2008. By Michael Zanetti
-
fix whitespace
Unmerged revisions
Preview Diff
1 | === modified file 'plugins/AccountsService/AccountsService.cpp' |
2 | --- plugins/AccountsService/AccountsService.cpp 2016-03-15 20:13:36 +0000 |
3 | +++ plugins/AccountsService/AccountsService.cpp 2016-03-15 20:13:37 +0000 |
4 | @@ -32,6 +32,7 @@ |
5 | |
6 | #define PROP_BACKGROUND_FILE QStringLiteral("BackgroundFile") |
7 | #define PROP_DEMO_EDGES QStringLiteral("demo-edges") |
8 | +#define PROP_DEMO_EDGES_COMPLETED QStringLiteral("DemoEdgesCompleted") |
9 | #define PROP_EMAIL QStringLiteral("Email") |
10 | #define PROP_ENABLE_INDICATORS_WHILE_LOCKED QStringLiteral("EnableIndicatorsWhileLocked") |
11 | #define PROP_ENABLE_LAUNCHER_WHILE_LOCKED QStringLiteral("EnableLauncherWhileLocked") |
12 | @@ -89,6 +90,7 @@ |
13 | registerProperty(IFACE_UBUNTU_SECURITY, PROP_PASSWORD_DISPLAY_HINT, QStringLiteral("passwordDisplayHintChanged")); |
14 | registerProperty(IFACE_UBUNTU_SECURITY_OLD, PROP_STATS_WELCOME_SCREEN, QStringLiteral("statsWelcomeScreenChanged")); |
15 | registerProperty(IFACE_UNITY, PROP_DEMO_EDGES, QStringLiteral("demoEdgesChanged")); |
16 | + registerProperty(IFACE_UNITY, PROP_DEMO_EDGES_COMPLETED, QStringLiteral("demoEdgesCompletedChanged")); |
17 | registerProperty(IFACE_UNITY_PRIVATE, PROP_FAILED_LOGINS, QStringLiteral("failedLoginsChanged")); |
18 | |
19 | registerProxy(IFACE_UBUNTU_INPUT, PROP_MOUSE_CURSOR_SPEED, |
20 | @@ -152,6 +154,20 @@ |
21 | setProperty(IFACE_UNITY, PROP_DEMO_EDGES, demoEdges); |
22 | } |
23 | |
24 | +QStringList AccountsService::demoEdgesCompleted() const |
25 | +{ |
26 | + auto value = getProperty(IFACE_UNITY, PROP_DEMO_EDGES_COMPLETED); |
27 | + return value.toStringList(); |
28 | +} |
29 | + |
30 | +void AccountsService::markDemoEdgeCompleted(const QString &edge) |
31 | +{ |
32 | + auto currentList = demoEdgesCompleted(); |
33 | + if (!currentList.contains(edge)) { |
34 | + setProperty(IFACE_UNITY, PROP_DEMO_EDGES_COMPLETED, currentList << edge); |
35 | + } |
36 | +} |
37 | + |
38 | bool AccountsService::enableLauncherWhileLocked() const |
39 | { |
40 | auto value = getProperty(IFACE_UBUNTU_SECURITY, PROP_ENABLE_LAUNCHER_WHILE_LOCKED); |
41 | |
42 | === modified file 'plugins/AccountsService/AccountsService.h' |
43 | --- plugins/AccountsService/AccountsService.h 2016-03-15 20:13:36 +0000 |
44 | +++ plugins/AccountsService/AccountsService.h 2016-03-15 20:13:37 +0000 |
45 | @@ -20,6 +20,7 @@ |
46 | #include <QHash> |
47 | #include <QObject> |
48 | #include <QString> |
49 | +#include <QStringList> |
50 | #include <QVariant> |
51 | |
52 | class AccountsServiceDBusAdaptor; |
53 | @@ -37,6 +38,9 @@ |
54 | READ demoEdges |
55 | WRITE setDemoEdges |
56 | NOTIFY demoEdgesChanged) |
57 | + Q_PROPERTY (QStringList demoEdgesCompleted |
58 | + READ demoEdgesCompleted |
59 | + NOTIFY demoEdgesCompletedChanged) |
60 | Q_PROPERTY (bool enableLauncherWhileLocked |
61 | READ enableLauncherWhileLocked |
62 | NOTIFY enableLauncherWhileLockedChanged) |
63 | @@ -82,6 +86,8 @@ |
64 | void setUser(const QString &user); |
65 | bool demoEdges() const; |
66 | void setDemoEdges(bool demoEdges); |
67 | + QStringList demoEdgesCompleted() const; |
68 | + Q_INVOKABLE void markDemoEdgeCompleted(const QString &edge); |
69 | bool enableLauncherWhileLocked() const; |
70 | bool enableIndicatorsWhileLocked() const; |
71 | QString backgroundFile() const; |
72 | @@ -101,6 +107,7 @@ |
73 | Q_SIGNALS: |
74 | void userChanged(); |
75 | void demoEdgesChanged(); |
76 | + void demoEdgesCompletedChanged(); |
77 | void enableLauncherWhileLockedChanged(); |
78 | void enableIndicatorsWhileLockedChanged(); |
79 | void backgroundFileChanged(); |
80 | |
81 | === modified file 'plugins/AccountsService/AccountsService.qmltypes' |
82 | --- plugins/AccountsService/AccountsService.qmltypes 2015-02-13 09:01:16 +0000 |
83 | +++ plugins/AccountsService/AccountsService.qmltypes 2016-03-15 20:13:37 +0000 |
84 | @@ -23,6 +23,7 @@ |
85 | } |
86 | Property { name: "user"; type: "string" } |
87 | Property { name: "demoEdges"; type: "bool" } |
88 | + Property { name: "demoEdgesCompleted"; type: "QStringList"; isReadonly: true } |
89 | Property { name: "enableLauncherWhileLocked"; type: "bool"; isReadonly: true } |
90 | Property { name: "enableIndicatorsWhileLocked"; type: "bool"; isReadonly: true } |
91 | Property { name: "backgroundFile"; type: "string"; isReadonly: true } |
92 | @@ -32,5 +33,9 @@ |
93 | Property { name: "hereEnabled"; type: "bool" } |
94 | Property { name: "hereLicensePath"; type: "string"; isReadonly: true } |
95 | Property { name: "hereLicensePathValid"; type: "bool"; isReadonly: true } |
96 | + Method { |
97 | + name: "markDemoEdgeCompleted" |
98 | + Parameter { name: "edge"; type: "string" } |
99 | + } |
100 | } |
101 | } |
102 | |
103 | === modified file 'plugins/AccountsService/com.canonical.unity.AccountsService.xml' |
104 | --- plugins/AccountsService/com.canonical.unity.AccountsService.xml 2015-02-04 15:12:36 +0000 |
105 | +++ plugins/AccountsService/com.canonical.unity.AccountsService.xml 2016-03-15 20:13:37 +0000 |
106 | @@ -14,6 +14,11 @@ |
107 | <annotation name="org.freedesktop.Accounts.DefaultValue" value="true"/> |
108 | </property> |
109 | |
110 | + <!-- List of tutorial pages that have been completed by the user --> |
111 | + <property name="DemoEdgesCompleted" type="as" access="readwrite"> |
112 | + <annotation name="org.freedesktop.Accounts.DefaultValue" value="[]"/> |
113 | + </property> |
114 | + |
115 | <property name="LauncherItems" type="aa{sv}" access="readwrite"> |
116 | <annotation name="org.freedesktop.Accounts.DefaultValue" value="[{'defaults': <true>}]"/> |
117 | </property> |
118 | |
119 | === modified file 'plugins/ScreenGrabber/screengrabber.cpp' |
120 | --- plugins/ScreenGrabber/screengrabber.cpp 2015-11-18 18:38:36 +0000 |
121 | +++ plugins/ScreenGrabber/screengrabber.cpp 2016-03-15 20:13:37 +0000 |
122 | @@ -46,12 +46,10 @@ |
123 | |
124 | QDir screenshotsDir; |
125 | if (qEnvironmentVariableIsSet("UNITY_TESTING")) { |
126 | - qDebug() << "Using test environment"; |
127 | QTemporaryDir tDir; |
128 | tDir.setAutoRemove(false); |
129 | screenshotsDir = tDir.path(); |
130 | } else { |
131 | - qDebug() << "Using real environment"; |
132 | screenshotsDir = QStandardPaths::writableLocation(QStandardPaths::PicturesLocation); |
133 | } |
134 | screenshotsDir.mkpath(QStringLiteral("Screenshots")); |
135 | |
136 | === modified file 'plugins/Ubuntu/Gestures/DirectionalDragArea.cpp' |
137 | --- plugins/Ubuntu/Gestures/DirectionalDragArea.cpp 2016-03-15 20:13:36 +0000 |
138 | +++ plugins/Ubuntu/Gestures/DirectionalDragArea.cpp 2016-03-15 20:13:37 +0000 |
139 | @@ -194,6 +194,26 @@ |
140 | } |
141 | } |
142 | |
143 | +bool DirectionalDragArea::monitorOnly() const |
144 | +{ |
145 | + return d->monitorOnly; |
146 | +} |
147 | + |
148 | +void DirectionalDragArea::setMonitorOnly(bool monitorOnly) |
149 | +{ |
150 | + if (d->monitorOnly != monitorOnly) { |
151 | + d->monitorOnly = monitorOnly; |
152 | + |
153 | + if (monitorOnly && d->status == DirectionalDragAreaPrivate::Undecided) { |
154 | + TouchRegistry::instance()->removeCandidateOwnerForTouch(d->touchId, this); |
155 | + // We still wanna know when it ends for keeping the composition time window up-to-date |
156 | + TouchRegistry::instance()->addTouchWatcher(d->touchId, this); |
157 | + } |
158 | + |
159 | + Q_EMIT monitorOnlyChanged(monitorOnly); |
160 | + } |
161 | +} |
162 | + |
163 | void DirectionalDragArea::removeTimeConstraints() |
164 | { |
165 | d->setMaxTime(60 * 60 * 1000); |
166 | @@ -260,7 +280,10 @@ |
167 | unownedTouchEvent_undecided(unownedTouchEvent); |
168 | break; |
169 | default: // Recognized: |
170 | - // do nothing |
171 | + if (monitorOnly) { |
172 | + // Treat unowned event as if we owned it, but we are really just watching it |
173 | + touchEvent_recognized(event); |
174 | + } |
175 | break; |
176 | } |
177 | |
178 | @@ -311,7 +334,9 @@ |
179 | } |
180 | |
181 | if (movedFarEnoughAlongGestureAxis()) { |
182 | - TouchRegistry::instance()->requestTouchOwnership(touchId, q); |
183 | + if (!monitorOnly) { |
184 | + TouchRegistry::instance()->requestTouchOwnership(touchId, q); |
185 | + } |
186 | setStatus(Recognized); |
187 | setPublicPos(touchPoint->pos()); |
188 | setPublicScenePos(touchScenePos); |
189 | @@ -411,12 +436,21 @@ |
190 | if (recognitionIsDisabled()) { |
191 | // Behave like a dumb TouchArea |
192 | ddaDebug("Gesture recognition is disabled. Requesting touch ownership immediately."); |
193 | - TouchRegistry::instance()->requestTouchOwnership(touchId, q); |
194 | setStatus(Recognized); |
195 | - event->accept(); |
196 | + if (monitorOnly) { |
197 | + watchPressedTouchPoints(touchPoints); |
198 | + event->ignore(); |
199 | + } else { |
200 | + TouchRegistry::instance()->requestTouchOwnership(touchId, q); |
201 | + event->accept(); |
202 | + } |
203 | } else { |
204 | // just monitor the touch points for now. |
205 | - TouchRegistry::instance()->addCandidateOwnerForTouch(touchId, q); |
206 | + if (monitorOnly) { |
207 | + watchPressedTouchPoints(touchPoints); |
208 | + } else { |
209 | + TouchRegistry::instance()->addCandidateOwnerForTouch(touchId, q); |
210 | + } |
211 | |
212 | setStatus(Undecided); |
213 | // Let the item below have it. We will monitor it and grab it later if a gesture |
214 | @@ -893,5 +927,6 @@ |
215 | , recognitionTimer(nullptr) |
216 | , timeSource(new RealTimeSource) |
217 | , activeTouches(timeSource) |
218 | + , monitorOnly(false) |
219 | { |
220 | } |
221 | |
222 | === modified file 'plugins/Ubuntu/Gestures/DirectionalDragArea.h' |
223 | --- plugins/Ubuntu/Gestures/DirectionalDragArea.h 2015-05-11 07:49:36 +0000 |
224 | +++ plugins/Ubuntu/Gestures/DirectionalDragArea.h 2016-03-15 20:13:37 +0000 |
225 | @@ -77,6 +77,10 @@ |
226 | WRITE setImmediateRecognition |
227 | NOTIFY immediateRecognitionChanged) |
228 | |
229 | + // Whether we are merely monitoring touch events (in which case, we don't |
230 | + // claim ownership of the touch). |
231 | + Q_PROPERTY(bool monitorOnly READ monitorOnly WRITE setMonitorOnly NOTIFY monitorOnlyChanged) |
232 | + |
233 | Q_ENUMS(Direction) |
234 | public: |
235 | DirectionalDragArea(QQuickItem *parent = 0); |
236 | @@ -100,6 +104,9 @@ |
237 | bool immediateRecognition() const; |
238 | void setImmediateRecognition(bool enabled); |
239 | |
240 | + bool monitorOnly() const; |
241 | + void setMonitorOnly(bool monitorOnly); |
242 | + |
243 | bool event(QEvent *e) override; |
244 | |
245 | /* |
246 | @@ -123,6 +130,7 @@ |
247 | void touchSceneXChanged(qreal value); |
248 | void touchSceneYChanged(qreal value); |
249 | void immediateRecognitionChanged(bool value); |
250 | + void monitorOnlyChanged(bool value); |
251 | |
252 | protected: |
253 | void touchEvent(QTouchEvent *event) override; |
254 | |
255 | === modified file 'plugins/Ubuntu/Gestures/DirectionalDragArea_p.h' |
256 | --- plugins/Ubuntu/Gestures/DirectionalDragArea_p.h 2015-11-20 15:01:39 +0000 |
257 | +++ plugins/Ubuntu/Gestures/DirectionalDragArea_p.h 2016-03-15 20:13:37 +0000 |
258 | @@ -160,6 +160,8 @@ |
259 | |
260 | ActiveTouchesInfo activeTouches; |
261 | |
262 | + bool monitorOnly; |
263 | + |
264 | Q_SIGNALS: |
265 | void statusChanged(Status value); |
266 | }; |
267 | |
268 | === modified file 'plugins/Utils/CMakeLists.txt' |
269 | --- plugins/Utils/CMakeLists.txt 2016-03-15 20:13:36 +0000 |
270 | +++ plugins/Utils/CMakeLists.txt 2016-03-15 20:13:37 +0000 |
271 | @@ -17,7 +17,7 @@ |
272 | unitysortfilterproxymodelqml.cpp |
273 | Timer.cpp |
274 | unitymenumodelpaths.cpp |
275 | - windowkeysfilter.cpp |
276 | + windowinputfilter.cpp |
277 | windowscreenshotprovider.cpp |
278 | easingcurve.cpp |
279 | windowstatestorage.cpp |
280 | |
281 | === modified file 'plugins/Utils/Utils.qmltypes' |
282 | --- plugins/Utils/Utils.qmltypes 2015-09-03 11:08:46 +0000 |
283 | +++ plugins/Utils/Utils.qmltypes 2016-03-15 20:13:37 +0000 |
284 | @@ -147,10 +147,10 @@ |
285 | } |
286 | } |
287 | Component { |
288 | - name: "WindowKeysFilter" |
289 | + name: "WindowInputFilter" |
290 | defaultProperty: "data" |
291 | prototype: "QQuickItem" |
292 | - exports: ["Utils/WindowKeysFilter 0.1"] |
293 | + exports: ["Utils/WindowInputFilter 0.1"] |
294 | exportMetaObjectRevisions: [0] |
295 | } |
296 | Component { |
297 | |
298 | === modified file 'plugins/Utils/plugin.cpp' |
299 | --- plugins/Utils/plugin.cpp 2016-03-15 20:13:36 +0000 |
300 | +++ plugins/Utils/plugin.cpp 2016-03-15 20:13:37 +0000 |
301 | @@ -30,7 +30,7 @@ |
302 | #include "qlimitproxymodelqml.h" |
303 | #include "unitysortfilterproxymodelqml.h" |
304 | #include "unitymenumodelpaths.h" |
305 | -#include "windowkeysfilter.h" |
306 | +#include "windowinputfilter.h" |
307 | #include "windowscreenshotprovider.h" |
308 | #include "windowstatestorage.h" |
309 | #include "constants.h" |
310 | @@ -69,7 +69,7 @@ |
311 | qmlRegisterType<QLimitProxyModelQML>(uri, 0, 1, "LimitProxyModel"); |
312 | qmlRegisterType<UnitySortFilterProxyModelQML>(uri, 0, 1, "UnitySortFilterProxyModel"); |
313 | qmlRegisterType<UnityMenuModelPaths>(uri, 0, 1, "UnityMenuModelPaths"); |
314 | - qmlRegisterType<WindowKeysFilter>(uri, 0, 1, "WindowKeysFilter"); |
315 | + qmlRegisterType<WindowInputFilter>(uri, 0, 1, "WindowInputFilter"); |
316 | qmlRegisterType<EasingCurve>(uri, 0, 1, "EasingCurve"); |
317 | qmlRegisterSingletonType<WindowStateStorage>(uri, 0, 1, "WindowStateStorage", createWindowStateStorage); |
318 | qmlRegisterType<InputWatcher>(uri, 0, 1, "InputWatcher"); |
319 | |
320 | === renamed file 'plugins/Utils/windowkeysfilter.cpp' => 'plugins/Utils/windowinputfilter.cpp' |
321 | --- plugins/Utils/windowkeysfilter.cpp 2015-10-22 17:37:26 +0000 |
322 | +++ plugins/Utils/windowinputfilter.cpp 2016-03-15 20:13:37 +0000 |
323 | @@ -16,36 +16,34 @@ |
324 | * Author: Daniel d'Andrada <daniel.dandrada@canonical.com> |
325 | */ |
326 | |
327 | -#include "windowkeysfilter.h" |
328 | +#include "windowinputfilter.h" |
329 | |
330 | #include <QQuickWindow> |
331 | |
332 | -WindowKeysFilter::WindowKeysFilter(QQuickItem *parent) |
333 | +WindowInputFilter::WindowInputFilter(QQuickItem *parent) |
334 | : QQuickItem(parent), |
335 | - m_currentEventTimestamp(0) |
336 | + m_lastInputTimestamp(0) |
337 | { |
338 | connect(this, &QQuickItem::windowChanged, |
339 | - this, &WindowKeysFilter::setupFilterOnWindow); |
340 | + this, &WindowInputFilter::setupFilterOnWindow); |
341 | } |
342 | |
343 | -bool WindowKeysFilter::eventFilter(QObject *watched, QEvent *event) |
344 | +bool WindowInputFilter::eventFilter(QObject *watched, QEvent *event) |
345 | { |
346 | Q_ASSERT(!m_filteredWindow.isNull()); |
347 | Q_ASSERT(watched == static_cast<QObject*>(m_filteredWindow.data())); |
348 | Q_UNUSED(watched); |
349 | |
350 | + QInputEvent *inputEvent = dynamic_cast<QInputEvent*>(event); |
351 | + if (inputEvent) { |
352 | + m_lastInputTimestamp = inputEvent->timestamp(); |
353 | + Q_EMIT lastInputTimestampChanged(); |
354 | + } |
355 | + |
356 | if (event->type() == QEvent::KeyPress || event->type() == QEvent::KeyRelease) { |
357 | // Let QML see this event and decide if it does not want it |
358 | event->accept(); |
359 | - |
360 | - m_currentEventTimestamp = static_cast<QInputEvent*>(event)->timestamp(); |
361 | - Q_EMIT currentEventTimestampChanged(); |
362 | - |
363 | QCoreApplication::sendEvent(this, event); |
364 | - |
365 | - m_currentEventTimestamp = 0; |
366 | - Q_EMIT currentEventTimestampChanged(); |
367 | - |
368 | return event->isAccepted(); |
369 | } else { |
370 | // Not interested |
371 | @@ -53,7 +51,7 @@ |
372 | } |
373 | } |
374 | |
375 | -void WindowKeysFilter::setupFilterOnWindow(QQuickWindow *window) |
376 | +void WindowInputFilter::setupFilterOnWindow(QQuickWindow *window) |
377 | { |
378 | if (!m_filteredWindow.isNull()) { |
379 | m_filteredWindow->removeEventFilter(this); |
380 | @@ -66,7 +64,7 @@ |
381 | } |
382 | } |
383 | |
384 | -ulong WindowKeysFilter::currentEventTimestamp() const |
385 | +ulong WindowInputFilter::lastInputTimestamp() const |
386 | { |
387 | - return m_currentEventTimestamp; |
388 | + return m_lastInputTimestamp; |
389 | } |
390 | |
391 | === renamed file 'plugins/Utils/windowkeysfilter.h' => 'plugins/Utils/windowinputfilter.h' |
392 | --- plugins/Utils/windowkeysfilter.h 2015-10-22 17:37:26 +0000 |
393 | +++ plugins/Utils/windowinputfilter.h 2016-03-15 20:13:37 +0000 |
394 | @@ -16,8 +16,8 @@ |
395 | * Author: Daniel d'Andrada <daniel.dandrada@canonical.com> |
396 | */ |
397 | |
398 | -#ifndef UNITY_WINDOWKEYSFILTER_H |
399 | -#define UNITY_WINDOWKEYSFILTER_H |
400 | +#ifndef UNITY_WINDOWINPUTFILTER_H |
401 | +#define UNITY_WINDOWINPUTFILTER_H |
402 | |
403 | #include <QQuickItem> |
404 | #include <QPointer> |
405 | @@ -29,30 +29,30 @@ |
406 | accepted ones will be filtered out. Events are accepted by default, so make sure you reject |
407 | the keys you're not interested in. |
408 | |
409 | - If more than one WindowKeysFilter exist in the same QML scene (and thus in the same QQuickWindow) |
410 | + If more than one WindowInputFilter exist in the same QML scene (and thus in the same QQuickWindow) |
411 | they will be called in the order of creation, which can be tricky to assess. So the best practice |
412 | - is to have at most one WindowKeysFilter per QML scene. |
413 | + is to have at most one WindowInputFilter per QML scene. |
414 | */ |
415 | -class WindowKeysFilter : public QQuickItem |
416 | +class WindowInputFilter : public QQuickItem |
417 | { |
418 | Q_OBJECT |
419 | - Q_PROPERTY(ulong currentEventTimestamp READ currentEventTimestamp NOTIFY currentEventTimestampChanged) |
420 | + Q_PROPERTY(ulong lastInputTimestamp READ lastInputTimestamp NOTIFY lastInputTimestampChanged) |
421 | public: |
422 | - WindowKeysFilter(QQuickItem *parent = 0); |
423 | + WindowInputFilter(QQuickItem *parent = 0); |
424 | |
425 | bool eventFilter(QObject *watched, QEvent *event) override; |
426 | |
427 | - ulong currentEventTimestamp() const; |
428 | + ulong lastInputTimestamp() const; |
429 | |
430 | Q_SIGNALS: |
431 | - void currentEventTimestampChanged(); |
432 | + void lastInputTimestampChanged(); |
433 | |
434 | private Q_SLOTS: |
435 | void setupFilterOnWindow(QQuickWindow *window); |
436 | |
437 | private: |
438 | QPointer<QQuickWindow> m_filteredWindow; |
439 | - ulong m_currentEventTimestamp; |
440 | + ulong m_lastInputTimestamp; |
441 | }; |
442 | |
443 | -#endif // UNITY_WINDOWKEYSFILTER_H |
444 | +#endif // UNITY_WINDOWINPUTFILTER_H |
445 | |
446 | === modified file 'qml/Components/InputMethod.qml' |
447 | --- qml/Components/InputMethod.qml 2016-02-15 17:26:51 +0000 |
448 | +++ qml/Components/InputMethod.qml 2016-03-15 20:13:37 +0000 |
449 | @@ -51,7 +51,10 @@ |
450 | } |
451 | |
452 | state: { |
453 | - if (surfaceItem.surface && surfaceItem.surfaceState != Mir.MinimizedState && root.enabled) { |
454 | + if (surfaceItem.surface && |
455 | + surfaceItem.surfaceState != Mir.HiddenState && |
456 | + surfaceItem.surfaceState != Mir.MinimizedState && |
457 | + root.enabled) { |
458 | return "shown"; |
459 | } else { |
460 | return "hidden"; |
461 | |
462 | === modified file 'qml/Greeter/Greeter.qml' |
463 | --- qml/Greeter/Greeter.qml 2016-01-11 17:37:02 +0000 |
464 | +++ qml/Greeter/Greeter.qml 2016-03-15 20:13:37 +0000 |
465 | @@ -160,6 +160,14 @@ |
466 | return false; |
467 | } |
468 | } |
469 | + |
470 | + function checkForcedUnlock() { |
471 | + if (forcedUnlock && shown && loader.item) { |
472 | + // pretend we were just authenticated |
473 | + loader.item.notifyAuthenticationSucceeded(); |
474 | + loader.item.hide(); |
475 | + } |
476 | + } |
477 | } |
478 | |
479 | onLauncherOffsetChanged: { |
480 | @@ -168,12 +176,8 @@ |
481 | } |
482 | } |
483 | |
484 | - onForcedUnlockChanged: { |
485 | - if (forcedUnlock && shown) { |
486 | - // pretend we were just authenticated |
487 | - loader.item.notifyAuthenticationSucceeded(); |
488 | - } |
489 | - } |
490 | + onForcedUnlockChanged: d.checkForcedUnlock() |
491 | + Component.onCompleted: d.checkForcedUnlock() |
492 | |
493 | onRequiredChanged: { |
494 | if (required) { |
495 | |
496 | === modified file 'qml/Launcher/Launcher.qml' |
497 | --- qml/Launcher/Launcher.qml 2016-03-10 22:37:30 +0000 |
498 | +++ qml/Launcher/Launcher.qml 2016-03-15 20:13:37 +0000 |
499 | @@ -28,7 +28,6 @@ |
500 | property bool lockedVisible: false |
501 | property bool available: true // can be used to disable all interactions |
502 | property alias inverted: panel.inverted |
503 | - property bool shadeBackground: true // can be used to disable background shade when launcher is visible |
504 | |
505 | property int panelWidth: units.gu(10) |
506 | property int dragAreaWidth: units.gu(1) |
507 | @@ -298,7 +297,7 @@ |
508 | InverseMouseArea { |
509 | id: closeMouseArea |
510 | anchors.fill: panel |
511 | - enabled: root.shadeBackground && root.state == "visible" && (!root.lockedVisible || panel.highlightIndex >= -1) |
512 | + enabled: root.state == "visible" && (!root.lockedVisible || panel.highlightIndex >= -1) |
513 | visible: enabled |
514 | onPressed: { |
515 | panel.highlightIndex = -2 |
516 | @@ -310,7 +309,7 @@ |
517 | id: backgroundShade |
518 | anchors.fill: parent |
519 | color: "black" |
520 | - opacity: root.shadeBackground && root.state == "visible" && !root.lockedVisible ? 0.6 : 0 |
521 | + opacity: root.state == "visible" && !root.lockedVisible ? 0.6 : 0 |
522 | |
523 | Behavior on opacity { NumberAnimation { duration: UbuntuAnimation.BriskDuration } } |
524 | } |
525 | |
526 | === modified file 'qml/Panel/IndicatorsMenu.qml' |
527 | --- qml/Panel/IndicatorsMenu.qml 2016-03-10 21:28:46 +0000 |
528 | +++ qml/Panel/IndicatorsMenu.qml 2016-03-15 20:13:37 +0000 |
529 | @@ -36,7 +36,6 @@ |
530 | readonly property bool partiallyOpened: unitProgress > 0 && unitProgress < 1.0 |
531 | readonly property bool fullyClosed: unitProgress == 0 |
532 | property bool enableHint: true |
533 | - property bool contentEnabled: true |
534 | property bool showOnClick: true |
535 | property color panelColor: UbuntuColors.jet |
536 | |
537 | @@ -86,7 +85,6 @@ |
538 | height: openedHeight - bar.height - handle.height |
539 | indicatorsModel: root.indicatorsModel |
540 | visible: root.unitProgress > 0 |
541 | - enabled: contentEnabled |
542 | currentMenuIndex: bar.currentItemIndex |
543 | } |
544 | |
545 | |
546 | === modified file 'qml/Shell.qml' |
547 | --- qml/Shell.qml 2016-03-15 20:13:36 +0000 |
548 | +++ qml/Shell.qml 2016-03-15 20:13:37 +0000 |
549 | @@ -24,7 +24,7 @@ |
550 | import Ubuntu.Telephony 0.1 as Telephony |
551 | import Unity.Connectivity 0.1 |
552 | import Unity.Launcher 0.1 |
553 | -import GlobalShortcut 1.0 // has to be before Utils, because of WindowKeysFilter |
554 | +import GlobalShortcut 1.0 // has to be before Utils, because of WindowInputFilter |
555 | import GSettings 1.0 |
556 | import Utils 0.1 |
557 | import Powerd 0.1 |
558 | @@ -167,12 +167,13 @@ |
559 | } |
560 | |
561 | GlobalShortcut { |
562 | - // dummy shortcut to force creation of GlobalShortcutRegistry before WindowKeyFilter |
563 | + // dummy shortcut to force creation of GlobalShortcutRegistry before WindowInputFilter |
564 | } |
565 | |
566 | - WindowKeysFilter { |
567 | - Keys.onPressed: physicalKeysMapper.onKeyPressed(event, currentEventTimestamp); |
568 | - Keys.onReleased: physicalKeysMapper.onKeyReleased(event, currentEventTimestamp); |
569 | + WindowInputFilter { |
570 | + id: inputFilter |
571 | + Keys.onPressed: physicalKeysMapper.onKeyPressed(event, lastInputTimestamp); |
572 | + Keys.onReleased: physicalKeysMapper.onKeyReleased(event, lastInputTimestamp); |
573 | } |
574 | |
575 | WindowInputMonitor { |
576 | @@ -205,7 +206,7 @@ |
577 | onFocusedApplicationIdChanged: { |
578 | var appId = ApplicationManager.focusedApplicationId; |
579 | |
580 | - if (tutorial.running && appId != "" && appId != "unity8-dash") { |
581 | + if (wizard.active && appId != "" && appId != "unity8-dash") { |
582 | // If this happens on first boot, we may be in edge |
583 | // tutorial or wizard while receiving a call. But a call |
584 | // is more important than wizard so just bail out of those. |
585 | @@ -246,7 +247,7 @@ |
586 | property string usageScenario: shell.usageScenario === "phone" || greeter.hasLockedApp |
587 | ? "phone" |
588 | : shell.usageScenario |
589 | - source: { |
590 | + readonly property string qmlComponent: { |
591 | if(shell.mode === "greeter") { |
592 | return "Stages/ShimStage.qml" |
593 | } else if (applicationsDisplayLoader.usageScenario === "phone") { |
594 | @@ -257,9 +258,12 @@ |
595 | return "Stages/DesktopStage.qml"; |
596 | } |
597 | } |
598 | + onQmlComponentChanged: { |
599 | + if (item) item.stageAboutToBeUnloaded(); |
600 | + source = qmlComponent; |
601 | + } |
602 | |
603 | - property bool interactive: tutorial.spreadEnabled |
604 | - && (!greeter || !greeter.shown) |
605 | + property bool interactive: (!greeter || !greeter.shown) |
606 | && panel.indicators.fullyClosed |
607 | && launcher.progress == 0 |
608 | && !notifications.useModal |
609 | @@ -353,30 +357,6 @@ |
610 | value: shell.usageScenario == "desktop" && !settings.autohideLauncher ? launcher.panelWidth: 0 |
611 | } |
612 | } |
613 | - |
614 | - Tutorial { |
615 | - id: tutorial |
616 | - objectName: "tutorial" |
617 | - anchors.fill: parent |
618 | - |
619 | - // EdgeDragAreas don't work with mice. So to avoid trapping the user, |
620 | - // we skip the tutorial on the Desktop to avoid using them. The |
621 | - // Desktop doesn't use the same spread design anyway. The tutorial is |
622 | - // all a bit of a placeholder on non-phone form factors right now. |
623 | - // When the design team gives us more guidance, we can do something |
624 | - // more clever here. |
625 | - active: usageScenario != "desktop" && AccountsService.demoEdges |
626 | - |
627 | - paused: lightDM.greeter.active |
628 | - launcher: launcher |
629 | - panel: panel |
630 | - edgeSize: shell.edgeSize |
631 | - |
632 | - onFinished: { |
633 | - AccountsService.demoEdges = false; |
634 | - active = false; // for immediate response / if AS is having problems |
635 | - } |
636 | - } |
637 | } |
638 | |
639 | InputMethod { |
640 | @@ -387,7 +367,7 @@ |
641 | topMargin: panel.panelHeight |
642 | leftMargin: launcher.lockedVisible ? launcher.panelWidth : 0 |
643 | } |
644 | - z: notifications.useModal || panel.indicators.shown || wizard.active ? overlay.z + 1 : overlay.z - 1 |
645 | + z: notifications.useModal || panel.indicators.shown || wizard.active || tutorial.running ? overlay.z + 1 : overlay.z - 1 |
646 | } |
647 | |
648 | Connections { |
649 | @@ -418,7 +398,7 @@ |
650 | hides: [launcher, panel.indicators] |
651 | tabletMode: shell.usageScenario != "phone" |
652 | launcherOffset: launcher.progress |
653 | - forcedUnlock: tutorial.running |
654 | + forcedUnlock: wizard.active |
655 | background: wallpaperResolver.background |
656 | |
657 | // avoid overlapping with Launcher's edge drag area |
658 | @@ -475,7 +455,7 @@ |
659 | |
660 | onStatusChanged: { |
661 | if (Powerd.status === Powerd.Off && reason !== Powerd.Proximity && |
662 | - !callManager.hasCalls && !tutorial.running) { |
663 | + !callManager.hasCalls && !wizard.active) { |
664 | // We don't want to simply call greeter.showNow() here, because |
665 | // that will take too long. Qt will delay button event |
666 | // handling until the greeter is done loading and may think the |
667 | @@ -491,10 +471,6 @@ |
668 | } |
669 | |
670 | function showHome() { |
671 | - if (tutorial.running) { |
672 | - return |
673 | - } |
674 | - |
675 | greeter.notifyAboutToFocusApp("unity8-dash"); |
676 | |
677 | var animate = !lightDM.greeter.active && !stages.shown |
678 | @@ -528,7 +504,6 @@ |
679 | available: tutorial.panelEnabled |
680 | && ((!greeter || !greeter.locked) || AccountsService.enableIndicatorsWhileLocked) |
681 | && (!greeter || !greeter.hasLockedApp) |
682 | - contentEnabled: tutorial.panelContentEnabled |
683 | width: parent.width > units.gu(60) ? units.gu(40) : parent.width |
684 | |
685 | minimizedPanelHeight: units.gu(3) |
686 | @@ -567,7 +542,6 @@ |
687 | && (!greeter.locked || AccountsService.enableLauncherWhileLocked) |
688 | && !greeter.hasLockedApp |
689 | inverted: shell.usageScenario !== "desktop" |
690 | - shadeBackground: !tutorial.running |
691 | superPressed: physicalKeysMapper.superPressed |
692 | superTabPressed: physicalKeysMapper.superTabPressed |
693 | panelWidth: units.gu(settings.launcherWidth) |
694 | @@ -581,10 +555,8 @@ |
695 | } |
696 | } |
697 | onLauncherApplicationSelected: { |
698 | - if (!tutorial.running) { |
699 | - greeter.notifyAboutToFocusApp(appId); |
700 | - shell.activateApplication(appId) |
701 | - } |
702 | + greeter.notifyAboutToFocusApp(appId); |
703 | + shell.activateApplication(appId); |
704 | } |
705 | onShownChanged: { |
706 | if (shown) { |
707 | @@ -624,6 +596,20 @@ |
708 | } |
709 | } |
710 | |
711 | + Tutorial { |
712 | + id: tutorial |
713 | + objectName: "tutorial" |
714 | + anchors.fill: parent |
715 | + |
716 | + paused: callManager.hasCalls || greeter.shown |
717 | + keyboardVisible: inputMethod.state === "shown" |
718 | + usageScenario: shell.usageScenario |
719 | + lastInputTimestamp: inputFilter.lastInputTimestamp |
720 | + launcher: launcher |
721 | + panel: panel |
722 | + stage: applicationsDisplayLoader.item |
723 | + } |
724 | + |
725 | Wizard { |
726 | id: wizard |
727 | objectName: "wizard" |
728 | |
729 | === modified file 'qml/Stages/AbstractStage.qml' |
730 | --- qml/Stages/AbstractStage.qml 2016-03-15 20:13:36 +0000 |
731 | +++ qml/Stages/AbstractStage.qml 2016-03-15 20:13:37 +0000 |
732 | @@ -28,6 +28,7 @@ |
733 | property url background |
734 | property bool beingResized |
735 | property int dragAreaWidth |
736 | + property real dragProgress // How far left the stage has been dragged, used externally by tutorial code |
737 | property bool interactive |
738 | property real inverseProgress // This is the progress for left edge drags, in pixels. |
739 | property bool keepDashRunning: true |
740 | @@ -51,6 +52,8 @@ |
741 | | Qt.InvertedPortraitOrientation |
742 | | Qt.InvertedLandscapeOrientation |
743 | |
744 | + signal stageAboutToBeUnloaded |
745 | + |
746 | // Shared code for use in stage implementations |
747 | GSettings { |
748 | id: lifecycleExceptions |
749 | |
750 | === modified file 'qml/Stages/ApplicationWindow.qml' |
751 | --- qml/Stages/ApplicationWindow.qml 2016-03-15 20:13:36 +0000 |
752 | +++ qml/Stages/ApplicationWindow.qml 2016-03-15 20:13:37 +0000 |
753 | @@ -60,7 +60,6 @@ |
754 | readonly property color splashColor: root.application ? root.application.splashColor : "#00000000" |
755 | readonly property color splashColorHeader: root.application ? root.application.splashColorHeader : "#00000000" |
756 | readonly property color splashColorFooter: root.application ? root.application.splashColorFooter : "#00000000" |
757 | - readonly property url defaultScreenshot: (root.application && root.application.defaultScreenshot !== undefined) ? root.application.defaultScreenshot : "" |
758 | |
759 | // Whether the Application had a surface before but lost it. |
760 | property bool hadSurface: sessionContainer.surfaceContainer.hadSurface |
761 | @@ -112,7 +111,6 @@ |
762 | Image { |
763 | id: screenshotImage |
764 | objectName: "screenshotImage" |
765 | - source: d.defaultScreenshot |
766 | anchors.fill: parent |
767 | antialiasing: !root.interactive |
768 | |
769 | |
770 | === modified file 'qml/Stages/DesktopStage.qml' |
771 | --- qml/Stages/DesktopStage.qml 2016-03-10 22:37:38 +0000 |
772 | +++ qml/Stages/DesktopStage.qml 2016-03-15 20:13:37 +0000 |
773 | @@ -255,8 +255,8 @@ |
774 | focus: appId === priv.focusedAppId |
775 | width: decoratedWindow.width |
776 | height: decoratedWindow.height |
777 | - property alias requestedWidth: decoratedWindow.requestedWidth |
778 | - property alias requestedHeight: decoratedWindow.requestedHeight |
779 | + property int requestedWidth: -1 |
780 | + property int requestedHeight: -1 |
781 | property alias minimumWidth: decoratedWindow.minimumWidth |
782 | property alias minimumHeight: decoratedWindow.minimumHeight |
783 | property alias maximumWidth: decoratedWindow.maximumWidth |
784 | @@ -388,20 +388,40 @@ |
785 | PropertyChanges { |
786 | target: appDelegate; |
787 | x: root.leftMargin; y: 0; |
788 | - requestedWidth: appContainer.width - root.leftMargin; requestedHeight: appContainer.height; |
789 | visuallyMinimized: false; |
790 | visuallyMaximized: true |
791 | } |
792 | + PropertyChanges { |
793 | + target: decoratedWindow |
794 | + requestedWidth: root.width; |
795 | + requestedHeight: root.height; |
796 | + } |
797 | }, |
798 | State { |
799 | name: "maximizedLeft"; when: appDelegate.maximizedLeft && !appDelegate.minimized |
800 | - PropertyChanges { target: appDelegate; x: root.leftMargin; y: PanelState.panelHeight; |
801 | - requestedWidth: (appContainer.width - root.leftMargin)/2; requestedHeight: appContainer.height - PanelState.panelHeight } |
802 | + PropertyChanges { |
803 | + target: appDelegate |
804 | + x: root.leftMargin |
805 | + y: PanelState.panelHeight |
806 | + } |
807 | + PropertyChanges { |
808 | + target: decoratedWindow |
809 | + requestedWidth: (appContainer.width - root.leftMargin)/2 |
810 | + requestedHeight: appContainer.height - PanelState.panelHeight |
811 | + } |
812 | }, |
813 | State { |
814 | name: "maximizedRight"; when: appDelegate.maximizedRight && !appDelegate.minimized |
815 | - PropertyChanges { target: appDelegate; x: (appContainer.width + root.leftMargin)/2; y: PanelState.panelHeight; |
816 | - requestedWidth: (appContainer.width - root.leftMargin)/2; requestedHeight: appContainer.height - PanelState.panelHeight } |
817 | + PropertyChanges { |
818 | + target: appDelegate; |
819 | + x: (appContainer.width + root.leftMargin)/2 |
820 | + y: PanelState.panelHeight |
821 | + } |
822 | + PropertyChanges { |
823 | + target: decoratedWindow |
824 | + requestedWidth: (appContainer.width - root.leftMargin)/2 |
825 | + requestedHeight: appContainer.height - PanelState.panelHeight |
826 | + } |
827 | }, |
828 | State { |
829 | name: "minimized"; when: appDelegate.minimized |
830 | @@ -421,13 +441,17 @@ |
831 | enabled: appDelegate.animationsEnabled |
832 | PropertyAction { target: appDelegate; properties: "visuallyMinimized,visuallyMaximized" } |
833 | UbuntuNumberAnimation { target: appDelegate; properties: "x,y,opacity,requestedWidth,requestedHeight,scale"; duration: UbuntuAnimation.FastDuration } |
834 | + UbuntuNumberAnimation { target: decoratedWindow; properties: "requestedWidth,requestedHeight"; duration: UbuntuAnimation.FastDuration } |
835 | }, |
836 | Transition { |
837 | to: "minimized" |
838 | enabled: appDelegate.animationsEnabled |
839 | PropertyAction { target: appDelegate; property: "visuallyMaximized" } |
840 | SequentialAnimation { |
841 | - UbuntuNumberAnimation { target: appDelegate; properties: "x,y,opacity,requestedWidth,requestedHeight,scale"; duration: UbuntuAnimation.FastDuration } |
842 | + ParallelAnimation { |
843 | + UbuntuNumberAnimation { target: appDelegate; properties: "x,y,opacity,scale"; duration: UbuntuAnimation.FastDuration } |
844 | + UbuntuNumberAnimation { target: decoratedWindow; properties: "requestedWidth,requestedHeight"; duration: UbuntuAnimation.FastDuration } |
845 | + } |
846 | PropertyAction { target: appDelegate; property: "visuallyMinimized" } |
847 | ScriptAction { |
848 | script: { |
849 | @@ -443,7 +467,10 @@ |
850 | enabled: appDelegate.animationsEnabled |
851 | PropertyAction { target: appDelegate; property: "visuallyMinimized" } |
852 | SequentialAnimation { |
853 | - UbuntuNumberAnimation { target: appDelegate; properties: "x,y,opacity,requestedWidth,requestedHeight,scale"; duration: UbuntuAnimation.FastDuration } |
854 | + ParallelAnimation { |
855 | + UbuntuNumberAnimation { target: appDelegate; properties: "x,y,opacity,scale"; duration: UbuntuAnimation.FastDuration } |
856 | + UbuntuNumberAnimation { target: decoratedWindow; properties: "requestedWidth,requestedHeight"; duration: UbuntuAnimation.FastDuration } |
857 | + } |
858 | PropertyAction { target: appDelegate; property: "visuallyMaximized" } |
859 | } |
860 | } |
861 | @@ -458,6 +485,7 @@ |
862 | } |
863 | |
864 | WindowResizeArea { |
865 | + id: resizeArea |
866 | objectName: "windowResizeArea" |
867 | target: appDelegate |
868 | minWidth: units.gu(10) |
869 | @@ -469,6 +497,21 @@ |
870 | leftMargin: root.leftMargin |
871 | |
872 | onPressed: { ApplicationManager.focusApplication(model.appId) } |
873 | + |
874 | + property bool saveStateOnDestruction: true |
875 | + Connections { |
876 | + target: root |
877 | + onStageAboutToBeUnloaded: { |
878 | + resizeArea.saveWindowState(); |
879 | + resizeArea.saveStateOnDestruction = false; |
880 | + fullscreenPolicy.active = false; |
881 | + } |
882 | + } |
883 | + Component.onDestruction: { |
884 | + if (saveStateOnDestruction) { |
885 | + saveWindowState(); |
886 | + } |
887 | + } |
888 | } |
889 | |
890 | DecoratedWindow { |
891 | @@ -480,12 +523,21 @@ |
892 | active: ApplicationManager.focusedApplicationId === model.appId |
893 | focus: true |
894 | |
895 | + requestedWidth: appDelegate.requestedWidth |
896 | + requestedHeight: appDelegate.requestedHeight |
897 | + |
898 | onClose: ApplicationManager.stopApplication(model.appId) |
899 | onMaximize: appDelegate.maximized || appDelegate.maximizedLeft || appDelegate.maximizedRight |
900 | ? appDelegate.restoreFromMaximized() : appDelegate.maximize() |
901 | onMinimize: appDelegate.minimize() |
902 | onDecorationPressed: { ApplicationManager.focusApplication(model.appId) } |
903 | } |
904 | + |
905 | + WindowedFullscreenPolicy { |
906 | + id: fullscreenPolicy |
907 | + active: true |
908 | + application: decoratedWindow.application |
909 | + } |
910 | } |
911 | } |
912 | } |
913 | |
914 | === modified file 'qml/Stages/PhoneStage.qml' |
915 | --- qml/Stages/PhoneStage.qml 2016-03-10 09:19:38 +0000 |
916 | +++ qml/Stages/PhoneStage.qml 2016-03-15 20:13:37 +0000 |
917 | @@ -120,14 +120,11 @@ |
918 | : (Qt.PortraitOrientation | Qt.LandscapeOrientation |
919 | | Qt.InvertedPortraitOrientation | Qt.InvertedLandscapeOrientation) |
920 | |
921 | - // How far left the stage has been dragged |
922 | - readonly property real dragProgress: spreadRepeater.count > 0 ? -spreadRepeater.itemAt(0).xTranslate : 0 |
923 | + // How far left the stage has been dragged, used externally by tutorial code |
924 | + dragProgress: spreadRepeater.count > 0 ? spreadRepeater.itemAt(0).animatedProgress : 0 |
925 | |
926 | readonly property alias dragging: spreadDragArea.dragging |
927 | |
928 | - // Only used by the tutorial right now, when it is teasing the right edge |
929 | - property real dragAreaOverlap |
930 | - |
931 | signal opened() |
932 | |
933 | function select(appId) { |
934 | @@ -629,6 +626,15 @@ |
935 | property: "focusedAppOrientationChangesEnabled" |
936 | value: orientationChangesEnabled |
937 | } |
938 | + |
939 | + StagedFullscreenPolicy { |
940 | + id: fullscreenPolicy |
941 | + application: appDelegate.application |
942 | + } |
943 | + Connections { |
944 | + target: root |
945 | + onStageAboutToBeUnloaded: fullscreenPolicy.active = false |
946 | + } |
947 | } |
948 | } |
949 | } |
950 | @@ -647,7 +653,7 @@ |
951 | direction: Direction.Leftwards |
952 | enabled: (spreadView.phase != 2 && root.spreadEnabled) || dragging |
953 | |
954 | - anchors { top: parent.top; right: parent.right; bottom: parent.bottom; rightMargin: -root.dragAreaOverlap } |
955 | + anchors { top: parent.top; right: parent.right; bottom: parent.bottom; } |
956 | width: root.dragAreaWidth |
957 | |
958 | property var gesturePoints: new Array() |
959 | |
960 | === added file 'qml/Stages/StagedFullscreenPolicy.qml' |
961 | --- qml/Stages/StagedFullscreenPolicy.qml 1970-01-01 00:00:00 +0000 |
962 | +++ qml/Stages/StagedFullscreenPolicy.qml 2016-03-15 20:13:37 +0000 |
963 | @@ -0,0 +1,58 @@ |
964 | +/* |
965 | + * Copyright (C) 2016 Canonical, Ltd. |
966 | + * |
967 | + * This program is free software; you can redistribute it and/or modify |
968 | + * it under the terms of the GNU General Public License as published by |
969 | + * the Free Software Foundation; version 3. |
970 | + * |
971 | + * This program is distributed in the hope that it will be useful, |
972 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
973 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
974 | + * GNU General Public License for more details. |
975 | + * |
976 | + * You should have received a copy of the GNU General Public License |
977 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
978 | + */ |
979 | + |
980 | +import QtQuick 2.4 |
981 | +import Unity.Application 0.1 |
982 | + |
983 | +// This component will change the state of the surface based on the surface |
984 | +// state and shell chrome. |
985 | +// |
986 | +// Chrome changed to LowChrome -> server sets client window state to "fullscreen" |
987 | +// Chrome changed to NormalChrome -> server sets client window to "restored" state. |
988 | +// Chrome set and state change to restored -> server RESETS client window state to "fullscreen" |
989 | +// Chrome not set and state change to restored -> client window stays "restored" |
990 | +// Chrome not set and state change to fulscreen -> client window stays "fullscreen" |
991 | +QtObject { |
992 | + property bool active: true |
993 | + property QtObject application: null |
994 | + |
995 | + readonly property var lastSurface: application && application.session ? |
996 | + application.session.lastSurface : null |
997 | + onLastSurfaceChanged: { |
998 | + if (!active || !lastSurface) return; |
999 | + if (lastSurface.shellChrome === Mir.LowChrome) { |
1000 | + lastSurface.state = Mir.FullscreenState; |
1001 | + } |
1002 | + } |
1003 | + |
1004 | + property var _connections: Connections { |
1005 | + target: lastSurface |
1006 | + onShellChromeChanged: { |
1007 | + if (!active || !lastSurface) return; |
1008 | + if (lastSurface.shellChrome === Mir.LowChrome) { |
1009 | + lastSurface.state = Mir.FullscreenState; |
1010 | + } else { |
1011 | + lastSurface.state = Mir.RestoredState; |
1012 | + } |
1013 | + } |
1014 | + onStateChanged: { |
1015 | + if (!active) return; |
1016 | + if (lastSurface.state === Mir.RestoredState && lastSurface.shellChrome === Mir.LowChrome) { |
1017 | + lastSurface.state = Mir.FullscreenState; |
1018 | + } |
1019 | + } |
1020 | + } |
1021 | +} |
1022 | |
1023 | === modified file 'qml/Stages/TabletStage.qml' |
1024 | --- qml/Stages/TabletStage.qml 2016-03-15 20:13:36 +0000 |
1025 | +++ qml/Stages/TabletStage.qml 2016-03-15 20:13:37 +0000 |
1026 | @@ -27,6 +27,9 @@ |
1027 | objectName: "stages" |
1028 | anchors.fill: parent |
1029 | |
1030 | + property alias sideStageVisible: spreadView.sideStageVisible |
1031 | + property alias sideStageWidth: spreadView.sideStageWidth |
1032 | + |
1033 | // Functions to be called from outside |
1034 | function updateFocusedAppOrientation() { |
1035 | var mainStageAppIndex = priv.indexOf(priv.mainStageAppId); |
1036 | @@ -97,6 +100,9 @@ |
1037 | } |
1038 | } |
1039 | |
1040 | + // How far left the stage has been dragged, used externally by tutorial code |
1041 | + dragProgress: spreadRepeater.count > 0 ? spreadRepeater.itemAt(0).animatedProgress : 0 |
1042 | + |
1043 | onWidthChanged: { |
1044 | spreadView.selectedIndex = -1; |
1045 | spreadView.phase = 0; |
1046 | @@ -318,8 +324,6 @@ |
1047 | contentX: -shift |
1048 | |
1049 | property int tileDistance: units.gu(20) |
1050 | - property int sideStageWidth: units.gu(40) |
1051 | - property bool sideStageVisible: priv.sideStageAppId |
1052 | |
1053 | // This indicates when the spreadView is active. That means, all the animations |
1054 | // are activated and tiles need to line up for the spread. |
1055 | @@ -382,6 +386,9 @@ |
1056 | } |
1057 | |
1058 | property real sideStageDragProgress: sideStage.progress |
1059 | + property bool sideStageVisible: priv.sideStageAppId |
1060 | + property real sideStageWidth: units.gu(40) |
1061 | + |
1062 | property bool surfaceDragging: triGestureArea.recognisedDrag |
1063 | |
1064 | // In case the ApplicationManager already holds an app when starting up we're missing animations |
1065 | @@ -688,9 +695,6 @@ |
1066 | |
1067 | readonly property bool wantsMainStage: model.stage == ApplicationInfoInterface.MainStage |
1068 | |
1069 | - readonly property string appId: model.appId |
1070 | - readonly property bool isDash: model.appId == "unity8-dash" |
1071 | - |
1072 | stage: model.stage |
1073 | fullscreen: { |
1074 | if (mainApp && stage === ApplicationInfoInterface.SideStage) { |
1075 | @@ -947,6 +951,15 @@ |
1076 | period: (spreadView.positionMarker2 - spreadView.positionMarker1) / 3 |
1077 | progress: spreadTile.progress - spreadView.positionMarker1 |
1078 | } |
1079 | + |
1080 | + StagedFullscreenPolicy { |
1081 | + id: fullscreenPolicy |
1082 | + application: spreadTile.application |
1083 | + } |
1084 | + Connections { |
1085 | + target: root |
1086 | + onStageAboutToBeUnloaded: fullscreenPolicy.active = false |
1087 | + } |
1088 | } |
1089 | } |
1090 | } |
1091 | |
1092 | === modified file 'qml/Stages/WindowResizeArea.qml' |
1093 | --- qml/Stages/WindowResizeArea.qml 2016-03-10 22:43:31 +0000 |
1094 | +++ qml/Stages/WindowResizeArea.qml 2016-03-15 20:13:37 +0000 |
1095 | @@ -87,7 +87,7 @@ |
1096 | priv.updateNormalGeometry(); |
1097 | } |
1098 | |
1099 | - Component.onDestruction: { |
1100 | + function saveWindowState() { |
1101 | windowStateStorage.saveState(root.windowId, target.state == "maximized" ? WindowStateStorage.WindowStateMaximized : WindowStateStorage.WindowStateNormal) |
1102 | windowStateStorage.saveGeometry(root.windowId, Qt.rect(priv.normalX, priv.normalY, priv.normalWidth, priv.normalHeight)) |
1103 | } |
1104 | |
1105 | === added file 'qml/Stages/WindowedFullscreenPolicy.qml' |
1106 | --- qml/Stages/WindowedFullscreenPolicy.qml 1970-01-01 00:00:00 +0000 |
1107 | +++ qml/Stages/WindowedFullscreenPolicy.qml 2016-03-15 20:13:37 +0000 |
1108 | @@ -0,0 +1,41 @@ |
1109 | +/* |
1110 | + * Copyright (C) 2016 Canonical, Ltd. |
1111 | + * |
1112 | + * This program is free software; you can redistribute it and/or modify |
1113 | + * it under the terms of the GNU General Public License as published by |
1114 | + * the Free Software Foundation; version 3. |
1115 | + * |
1116 | + * This program is distributed in the hope that it will be useful, |
1117 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1118 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1119 | + * GNU General Public License for more details. |
1120 | + * |
1121 | + * You should have received a copy of the GNU General Public License |
1122 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1123 | + */ |
1124 | + |
1125 | +import QtQml 2.2 |
1126 | +import Unity.Application 0.1 |
1127 | + |
1128 | +// This component will change the state of the surface when the stage is loaded. |
1129 | +// |
1130 | +// On first surface load; if the surface is set to low chrome & fullscreen, the |
1131 | +// state of the window is returned to restored. |
1132 | +QtObject { |
1133 | + property bool active: true |
1134 | + property QtObject application: null |
1135 | + |
1136 | + readonly property var lastSurface: application && application.session ? |
1137 | + application.session.lastSurface : null |
1138 | + property bool _firstTimeSurface: true |
1139 | + |
1140 | + onLastSurfaceChanged: { |
1141 | + if (!active || !lastSurface) return; |
1142 | + if (!_firstTimeSurface) return; |
1143 | + _firstTimeSurface = false; |
1144 | + |
1145 | + if (lastSurface.state === Mir.FullscreenState && lastSurface.shellChrome === Mir.LowChrome) { |
1146 | + lastSurface.state = Mir.RestoredState; |
1147 | + } |
1148 | + } |
1149 | +} |
1150 | |
1151 | === removed file 'qml/Tutorial/Arrow.qml' |
1152 | --- qml/Tutorial/Arrow.qml 2015-07-15 15:07:19 +0000 |
1153 | +++ qml/Tutorial/Arrow.qml 1970-01-01 00:00:00 +0000 |
1154 | @@ -1,56 +0,0 @@ |
1155 | -/* |
1156 | - * Copyright (C) 2014 Canonical, Ltd. |
1157 | - * |
1158 | - * This program is free software; you can redistribute it and/or modify |
1159 | - * it under the terms of the GNU General Public License as published by |
1160 | - * the Free Software Foundation; version 3. |
1161 | - * |
1162 | - * This program is distributed in the hope that it will be useful, |
1163 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1164 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1165 | - * GNU General Public License for more details. |
1166 | - * |
1167 | - * You should have received a copy of the GNU General Public License |
1168 | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1169 | - */ |
1170 | - |
1171 | -import QtQuick 2.4 |
1172 | -import Ubuntu.Components 1.3 |
1173 | - |
1174 | -Item { |
1175 | - id: root |
1176 | - |
1177 | - property alias color: circle.color |
1178 | - |
1179 | - // Will make whole arrow darker |
1180 | - property real darkenBy: 0 |
1181 | - |
1182 | - property alias chevronOpacity: chevron.opacity |
1183 | - |
1184 | - //// |
1185 | - |
1186 | - Rectangle { |
1187 | - id: circle |
1188 | - anchors.fill: parent |
1189 | - radius: width / 2 |
1190 | - } |
1191 | - |
1192 | - Image { |
1193 | - id: chevron |
1194 | - anchors.centerIn: parent |
1195 | - source: Qt.resolvedUrl("graphics/chevron.png") |
1196 | - fillMode: Image.PreserveAspectFit |
1197 | - sourceSize.width: 152 |
1198 | - sourceSize.height: 152 |
1199 | - width: parent.width / 2 |
1200 | - height: parent.height / 2 |
1201 | - } |
1202 | - |
1203 | - Rectangle { |
1204 | - id: darkCircle |
1205 | - anchors.fill: parent |
1206 | - radius: width / 2 |
1207 | - color: "black" |
1208 | - opacity: root.darkenBy |
1209 | - } |
1210 | -} |
1211 | |
1212 | === added file 'qml/Tutorial/InactivityTimer.qml' |
1213 | --- qml/Tutorial/InactivityTimer.qml 1970-01-01 00:00:00 +0000 |
1214 | +++ qml/Tutorial/InactivityTimer.qml 2016-03-15 20:13:37 +0000 |
1215 | @@ -0,0 +1,62 @@ |
1216 | +/* |
1217 | + * Copyright (C) 2015 Canonical, Ltd. |
1218 | + * |
1219 | + * This program is free software; you can redistribute it and/or modify |
1220 | + * it under the terms of the GNU General Public License as published by |
1221 | + * the Free Software Foundation; version 3. |
1222 | + * |
1223 | + * This program is distributed in the hope that it will be useful, |
1224 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1225 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1226 | + * GNU General Public License for more details. |
1227 | + * |
1228 | + * You should have received a copy of the GNU General Public License |
1229 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1230 | + */ |
1231 | + |
1232 | +import QtQuick 2.4 |
1233 | +import Ubuntu.Components 1.3 |
1234 | + |
1235 | +Item { |
1236 | + readonly property alias running: internalTimer.running |
1237 | + property alias interval: internalTimer.interval |
1238 | + property var page |
1239 | + property int lastInputTimestamp |
1240 | + |
1241 | + function start() { |
1242 | + internalTimer.start(); |
1243 | + } |
1244 | + |
1245 | + //// |
1246 | + |
1247 | + onLastInputTimestampChanged: { |
1248 | + if (internalTimer.running) { |
1249 | + internalTimer.restart(); |
1250 | + } |
1251 | + } |
1252 | + |
1253 | + Connections { |
1254 | + target: page |
1255 | + onIsReadyChanged: { |
1256 | + if (page.isReady && internalTimer.running) { |
1257 | + internalTimer.restart(); |
1258 | + } |
1259 | + } |
1260 | + } |
1261 | + |
1262 | + Timer { |
1263 | + id: internalTimer |
1264 | + |
1265 | + interval: 3000 |
1266 | + |
1267 | + onTriggered: { |
1268 | + if (page.isReady) { |
1269 | + if (!page.shown) { |
1270 | + page.show(); |
1271 | + } |
1272 | + } else if (!page.skipped) { |
1273 | + restart(); |
1274 | + } |
1275 | + } |
1276 | + } |
1277 | +} |
1278 | |
1279 | === removed file 'qml/Tutorial/Slider.qml' |
1280 | --- qml/Tutorial/Slider.qml 2015-07-15 15:07:19 +0000 |
1281 | +++ qml/Tutorial/Slider.qml 1970-01-01 00:00:00 +0000 |
1282 | @@ -1,123 +0,0 @@ |
1283 | -/* |
1284 | - * Copyright (C) 2014 Canonical, Ltd. |
1285 | - * |
1286 | - * This program is free software; you can redistribute it and/or modify |
1287 | - * it under the terms of the GNU General Public License as published by |
1288 | - * the Free Software Foundation; version 3. |
1289 | - * |
1290 | - * This program is distributed in the hope that it will be useful, |
1291 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1292 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1293 | - * GNU General Public License for more details. |
1294 | - * |
1295 | - * You should have received a copy of the GNU General Public License |
1296 | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1297 | - */ |
1298 | - |
1299 | -import QtQuick 2.4 |
1300 | -import Ubuntu.Components 1.3 |
1301 | - |
1302 | -Item { |
1303 | - id: root |
1304 | - |
1305 | - // Whether this slider is short or long |
1306 | - property bool shortSwipe |
1307 | - |
1308 | - // How far the user has slid |
1309 | - property real offset |
1310 | - |
1311 | - // Set to true when slider is being used |
1312 | - property bool active |
1313 | - |
1314 | - // How far in percentage terms |
1315 | - readonly property real percent: d.slideOffset / target.x |
1316 | - |
1317 | - QtObject { |
1318 | - id: d |
1319 | - readonly property color trayColor: "#424141" |
1320 | - readonly property real margin: units.gu(0.5) |
1321 | - readonly property real arrowSize: root.height - margin * 2 |
1322 | - readonly property real dotSize: units.dp(1) |
1323 | - readonly property real slideOffset: MathUtils.clamp(root.offset - offscreenOffset, -offscreenOffset, target.x) |
1324 | - readonly property real offscreenOffset: units.gu(2) |
1325 | - } |
1326 | - |
1327 | - implicitWidth: shortSwipe ? units.gu(15) : units.gu(27.5) |
1328 | - implicitHeight: units.gu(6.5) |
1329 | - |
1330 | - Rectangle { |
1331 | - color: d.trayColor |
1332 | - anchors.fill: parent |
1333 | - anchors.rightMargin: clipBox.width - 1 |
1334 | - } |
1335 | - |
1336 | - // We want to have a circular border around the target. But we can't just |
1337 | - // do a radius on two of a rectangle's corners. So we clip a full circle. |
1338 | - Item { |
1339 | - id: clipBox |
1340 | - |
1341 | - clip: true |
1342 | - anchors.top: parent.top |
1343 | - anchors.bottom: parent.bottom |
1344 | - anchors.right: parent.right |
1345 | - width: parent.height / 2 |
1346 | - |
1347 | - Rectangle { |
1348 | - color: d.trayColor |
1349 | - anchors.top: parent.top |
1350 | - anchors.bottom: parent.bottom |
1351 | - anchors.right: parent.right |
1352 | - width: parent.width * 2 |
1353 | - radius: parent.width |
1354 | - } |
1355 | - } |
1356 | - |
1357 | - Arrow { |
1358 | - id: target |
1359 | - width: d.arrowSize |
1360 | - height: d.arrowSize |
1361 | - color: "#73000000" |
1362 | - chevronOpacity: 0.52 |
1363 | - anchors.right: parent.right |
1364 | - anchors.rightMargin: d.margin |
1365 | - anchors.verticalCenter: parent.verticalCenter |
1366 | - } |
1367 | - |
1368 | - Row { |
1369 | - anchors.left: handle.horizontalCenter |
1370 | - anchors.right: target.horizontalCenter |
1371 | - anchors.verticalCenter: parent.verticalCenter |
1372 | - |
1373 | - layoutDirection: Qt.RightToLeft |
1374 | - spacing: d.dotSize * 2 |
1375 | - |
1376 | - Repeater { |
1377 | - model: parent.width / (parent.spacing + d.dotSize) |
1378 | - Rectangle { |
1379 | - anchors.verticalCenter: parent ? parent.verticalCenter : undefined |
1380 | - height: d.dotSize |
1381 | - width: height |
1382 | - radius: width |
1383 | - color: "white" |
1384 | - opacity: 0.2 |
1385 | - } |
1386 | - } |
1387 | - } |
1388 | - |
1389 | - Arrow { |
1390 | - id: handle |
1391 | - width: d.arrowSize |
1392 | - height: d.arrowSize |
1393 | - color: UbuntuColors.orange |
1394 | - darkenBy: root.active ? 0.5 : 0 |
1395 | - anchors.left: parent.left |
1396 | - // We use a Translate transform rather than anchors.leftMargin because |
1397 | - // the latter has weird performance problems on the TutorialRight page. |
1398 | - transform: [ |
1399 | - Translate { |
1400 | - x: d.slideOffset |
1401 | - } |
1402 | - ] |
1403 | - anchors.verticalCenter: parent.verticalCenter |
1404 | - } |
1405 | -} |
1406 | |
1407 | === removed file 'qml/Tutorial/Tick.qml' |
1408 | --- qml/Tutorial/Tick.qml 2015-07-15 15:07:19 +0000 |
1409 | +++ qml/Tutorial/Tick.qml 1970-01-01 00:00:00 +0000 |
1410 | @@ -1,29 +0,0 @@ |
1411 | -/* |
1412 | - * Copyright (C) 2015 Canonical, Ltd. |
1413 | - * |
1414 | - * This program is free software; you can redistribute it and/or modify |
1415 | - * it under the terms of the GNU General Public License as published by |
1416 | - * the Free Software Foundation; version 3. |
1417 | - * |
1418 | - * This program is distributed in the hope that it will be useful, |
1419 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1420 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1421 | - * GNU General Public License for more details. |
1422 | - * |
1423 | - * You should have received a copy of the GNU General Public License |
1424 | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1425 | - */ |
1426 | - |
1427 | -import QtQuick 2.4 |
1428 | -import Ubuntu.Components 1.3 |
1429 | - |
1430 | -MouseArea { |
1431 | - implicitHeight: tick.height |
1432 | - implicitWidth: tick.width |
1433 | - Image { |
1434 | - id: tick |
1435 | - source: Qt.resolvedUrl("graphics/tick.png") |
1436 | - height: units.gu(6.5) |
1437 | - width: units.gu(6.5) |
1438 | - } |
1439 | -} |
1440 | |
1441 | === modified file 'qml/Tutorial/Tutorial.qml' |
1442 | --- qml/Tutorial/Tutorial.qml 2015-08-25 07:25:26 +0000 |
1443 | +++ qml/Tutorial/Tutorial.qml 2016-03-15 20:13:37 +0000 |
1444 | @@ -16,21 +16,29 @@ |
1445 | |
1446 | import QtQuick 2.4 |
1447 | import Ubuntu.Components 1.3 |
1448 | +import AccountsService 0.1 |
1449 | + |
1450 | +/** |
1451 | + * This object is always present, so it should be lean and mean. It will |
1452 | + * use a Loader to create the heavier tutorial pages if needed. |
1453 | + */ |
1454 | |
1455 | Item { |
1456 | id: root |
1457 | |
1458 | property alias active: loader.active |
1459 | - property bool paused |
1460 | - property real edgeSize |
1461 | |
1462 | property Item launcher |
1463 | property Item panel |
1464 | + property Item stage |
1465 | + property string usageScenario |
1466 | + property bool paused |
1467 | + property bool keyboardVisible |
1468 | + property int lastInputTimestamp |
1469 | |
1470 | readonly property bool launcherEnabled: loader.item ? loader.item.launcherEnabled : true |
1471 | readonly property bool spreadEnabled: loader.item ? loader.item.spreadEnabled : true |
1472 | readonly property bool panelEnabled: loader.item ? loader.item.panelEnabled : true |
1473 | - readonly property bool panelContentEnabled: loader.item ? loader.item.panelContentEnabled : true |
1474 | readonly property bool running: loader.item ? loader.item.running : false |
1475 | |
1476 | function finish() { |
1477 | @@ -39,24 +47,11 @@ |
1478 | } |
1479 | } |
1480 | |
1481 | - signal finished() |
1482 | - |
1483 | Loader { |
1484 | id: loader |
1485 | anchors.fill: parent |
1486 | source: "TutorialContent.qml" |
1487 | - |
1488 | - Binding { |
1489 | - target: loader.item |
1490 | - property: "paused" |
1491 | - value: root.paused |
1492 | - } |
1493 | - |
1494 | - Binding { |
1495 | - target: loader.item |
1496 | - property: "edgeSize" |
1497 | - value: root.edgeSize |
1498 | - } |
1499 | + active: AccountsService.demoEdges |
1500 | |
1501 | Binding { |
1502 | target: loader.item |
1503 | @@ -70,9 +65,39 @@ |
1504 | value: root.panel |
1505 | } |
1506 | |
1507 | + Binding { |
1508 | + target: loader.item |
1509 | + property: "stage" |
1510 | + value: root.stage |
1511 | + } |
1512 | + |
1513 | + Binding { |
1514 | + target: loader.item |
1515 | + property: "usageScenario" |
1516 | + value: root.usageScenario |
1517 | + } |
1518 | + |
1519 | + Binding { |
1520 | + target: loader.item |
1521 | + property: "paused" |
1522 | + value: root.paused |
1523 | + } |
1524 | + |
1525 | + Binding { |
1526 | + target: loader.item |
1527 | + property: "keyboardVisible" |
1528 | + value: root.keyboardVisible |
1529 | + } |
1530 | + |
1531 | + Binding { |
1532 | + target: loader.item |
1533 | + property: "lastInputTimestamp" |
1534 | + value: root.lastInputTimestamp |
1535 | + } |
1536 | + |
1537 | Connections { |
1538 | target: loader.item |
1539 | - onFinished: root.finished() |
1540 | + onFinished: AccountsService.demoEdges = false |
1541 | } |
1542 | } |
1543 | } |
1544 | |
1545 | === added file 'qml/Tutorial/TutorialBottom.qml' |
1546 | --- qml/Tutorial/TutorialBottom.qml 1970-01-01 00:00:00 +0000 |
1547 | +++ qml/Tutorial/TutorialBottom.qml 2016-03-15 20:13:37 +0000 |
1548 | @@ -0,0 +1,126 @@ |
1549 | +/* |
1550 | + * Copyright (C) 2015 Canonical, Ltd. |
1551 | + * |
1552 | + * This program is free software; you can redistribute it and/or modify |
1553 | + * it under the terms of the GNU General Public License as published by |
1554 | + * the Free Software Foundation; version 3. |
1555 | + * |
1556 | + * This program is distributed in the hope that it will be useful, |
1557 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1558 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1559 | + * GNU General Public License for more details. |
1560 | + * |
1561 | + * You should have received a copy of the GNU General Public License |
1562 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1563 | + */ |
1564 | + |
1565 | +import QtQuick 2.4 |
1566 | +import Ubuntu.Components 1.3 |
1567 | +import Ubuntu.Gestures 0.1 |
1568 | +import Unity.Application 0.1 |
1569 | + |
1570 | +TutorialPage { |
1571 | + id: root |
1572 | + |
1573 | + property string usageScenario |
1574 | + property var stage |
1575 | + property var application: null |
1576 | + |
1577 | + // This page is a bit fragile. It relies on knowing how the app beneath |
1578 | + // the shell will react to a drag. What we do is put a monitor-only DDA |
1579 | + // at the bottom of the page (so that we know when the drag is finished) |
1580 | + // and pass the events on through to the app. Thus, it sees the drag and |
1581 | + // brings its bottom edge up. |
1582 | + // |
1583 | + // Unfortunately, each app is on its own when implementing the bottom edge |
1584 | + // drag. Most share copied-and-pasted code right now, but they will |
1585 | + // eventually consolidate on a version of DirectionalDragArea that will |
1586 | + // land in the SDK (making our guessing job easier). Though, also in the |
1587 | + // future, this whole bottom tutorial component will also land in the SDK, |
1588 | + // rendering our version here obsolete. |
1589 | + // |
1590 | + // Anyway, for the moment, we base our guesses on the copied-and-pasted |
1591 | + // code used in several of the core apps and only bring this component |
1592 | + // up if we are in those core apps. |
1593 | + |
1594 | + readonly property real mainStageWidth: stage.width - sideStageWidth |
1595 | + readonly property real sideStageWidth: root.usageScenario === "tablet" && stage.sideStageVisible ? |
1596 | + stage.sideStageWidth : 0 |
1597 | + readonly property bool isMainStageApp: usageScenario !== "tablet" || |
1598 | + application.stage === ApplicationInfoInterface.MainStage |
1599 | + readonly property real dragAreaHeight: units.gu(3) // based on PageWithBottomEdge.qml |
1600 | + readonly property real targetDistance: height * 0.2 + dragAreaHeight // based on PageWithBottomEdge.qml |
1601 | + |
1602 | + opacityOverride: dragArea.dragging ? 1 - (-dragArea.distance / targetDistance) : 1 |
1603 | + |
1604 | + mouseArea { |
1605 | + anchors.bottomMargin: root.dragAreaHeight |
1606 | + } |
1607 | + |
1608 | + background { |
1609 | + sourceSize.height: 1916 |
1610 | + sourceSize.width: 1080 |
1611 | + source: Qt.resolvedUrl("graphics/background2.png") |
1612 | + rotation: 180 |
1613 | + } |
1614 | + |
1615 | + arrow { |
1616 | + anchors.bottom: root.bottom |
1617 | + anchors.bottomMargin: units.gu(3) |
1618 | + anchors.horizontalCenter: label.horizontalCenter |
1619 | + anchors.horizontalCenterOffset: -(label.width - label.contentWidth) / 2 |
1620 | + rotation: 90 |
1621 | + } |
1622 | + |
1623 | + label { |
1624 | + text: !application ? "" : |
1625 | + application.appId === "address-book-app" ? |
1626 | + i18n.tr("Swipe up to add a contact") : |
1627 | + application.appId === "com.ubuntu.calculator_calculator" ? |
1628 | + i18n.tr("Swipe up for favorite calculations") : |
1629 | + application.appId === "com.ubuntu.clock_clock" ? |
1630 | + i18n.tr("Swipe up to manage alarms") : |
1631 | + application.appId === "dialer-app" ? |
1632 | + i18n.tr("Swipe up for recent calls") : |
1633 | + application.appId === "messaging-app" ? |
1634 | + i18n.tr("Swipe up to create a message") : |
1635 | + i18n.tr("Swipe up to manage the app") // shouldn't be used |
1636 | + anchors.bottom: arrow.top |
1637 | + anchors.bottomMargin: units.gu(3) |
1638 | + anchors.left: root.left |
1639 | + anchors.leftMargin: (label.width - label.contentWidth) / 2 + sideMargin + |
1640 | + (isMainStageApp ? 0 : mainStageWidth) |
1641 | + width: (isMainStageApp ? mainStageWidth : sideStageWidth) - sideMargin * 2 |
1642 | + |
1643 | + readonly property real sideMargin: units.gu(4) |
1644 | + } |
1645 | + |
1646 | + // Watches drag events but does not intercept them, so that the app beneath |
1647 | + // will still drag the bottom edge up. |
1648 | + DirectionalDragArea { |
1649 | + id: dragArea |
1650 | + monitorOnly: true |
1651 | + direction: Direction.Upwards |
1652 | + anchors.left: parent.left |
1653 | + anchors.right: parent.right |
1654 | + anchors.bottom: parent.bottom |
1655 | + height: root.dragAreaHeight |
1656 | + |
1657 | + // Apps currently don't use DDA. DDA will stop a gesture if |
1658 | + // horizontal motion is detected. But our apps won't. So turn off |
1659 | + // that gesture cleverness on our part, it will only get us out of sync. |
1660 | + immediateRecognition: true |
1661 | + } |
1662 | + |
1663 | + MouseArea { |
1664 | + // A second mouse area because in tablet mode, we only want to let the |
1665 | + // user drag up on one of the stages, not both. So we want to cover |
1666 | + // the second bottom edge with an event eater. |
1667 | + enabled: root.usageScenario === "tablet" |
1668 | + height: root.dragAreaHeight |
1669 | + width: isMainStageApp ? sideStageWidth : mainStageWidth |
1670 | + anchors.bottom: parent.bottom |
1671 | + anchors.left: isMainStageApp ? undefined : parent.left |
1672 | + anchors.right: isMainStageApp ? parent.right : undefined |
1673 | + } |
1674 | +} |
1675 | |
1676 | === removed file 'qml/Tutorial/TutorialBottom.qml' |
1677 | --- qml/Tutorial/TutorialBottom.qml 2015-07-15 15:07:19 +0000 |
1678 | +++ qml/Tutorial/TutorialBottom.qml 1970-01-01 00:00:00 +0000 |
1679 | @@ -1,104 +0,0 @@ |
1680 | -/* |
1681 | - * Copyright (C) 2014 Canonical, Ltd. |
1682 | - * |
1683 | - * This program is free software; you can redistribute it and/or modify |
1684 | - * it under the terms of the GNU General Public License as published by |
1685 | - * the Free Software Foundation; version 3. |
1686 | - * |
1687 | - * This program is distributed in the hope that it will be useful, |
1688 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1689 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1690 | - * GNU General Public License for more details. |
1691 | - * |
1692 | - * You should have received a copy of the GNU General Public License |
1693 | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1694 | - */ |
1695 | - |
1696 | -import QtQuick 2.4 |
1697 | -import Ubuntu.Components 1.3 |
1698 | -import Ubuntu.Gestures 0.1 |
1699 | -import "../Components" |
1700 | -import "." as LocalComponents |
1701 | - |
1702 | -TutorialPage { |
1703 | - id: root |
1704 | - |
1705 | - property alias edgeSize: dragArea.height |
1706 | - |
1707 | - title: i18n.tr("Open special menus") |
1708 | - text: i18n.tr("Swipe up from the bottom edge.") |
1709 | - fullTextWidth: true |
1710 | - |
1711 | - SequentialAnimation { |
1712 | - id: teaseAnimation |
1713 | - paused: running && root.paused |
1714 | - running: !dragArea.useTouchY && slider.dragOffset === 0 |
1715 | - loops: Animation.Infinite |
1716 | - |
1717 | - UbuntuNumberAnimation { |
1718 | - target: slider |
1719 | - property: "teaseOffset" |
1720 | - to: units.gu(1) |
1721 | - duration: UbuntuAnimation.SleepyDuration |
1722 | - } |
1723 | - UbuntuNumberAnimation { |
1724 | - target: slider |
1725 | - property: "teaseOffset" |
1726 | - to: 0 |
1727 | - duration: UbuntuAnimation.SleepyDuration |
1728 | - } |
1729 | - } |
1730 | - |
1731 | - foreground { |
1732 | - children: [ |
1733 | - LocalComponents.Slider { |
1734 | - id: slider |
1735 | - anchors { |
1736 | - bottom: parent.bottom |
1737 | - bottomMargin: width / 2 - height / 2 |
1738 | - horizontalCenter: parent.horizontalCenter |
1739 | - } |
1740 | - rotation: -90 |
1741 | - offset: teaseOffset + dragOffset |
1742 | - active: dragArea.dragging |
1743 | - |
1744 | - property real teaseOffset |
1745 | - property real dragOffset: dragArea.useTouchY ? -dragArea.touchY : 0 |
1746 | - |
1747 | - Behavior on dragOffset { |
1748 | - id: offsetAnimation |
1749 | - UbuntuNumberAnimation {} |
1750 | - } |
1751 | - } |
1752 | - ] |
1753 | - } |
1754 | - |
1755 | - DirectionalDragArea { |
1756 | - id: dragArea |
1757 | - direction: Direction.Upwards |
1758 | - anchors { |
1759 | - bottom: parent.bottom |
1760 | - left: parent.left |
1761 | - right: parent.right |
1762 | - } |
1763 | - |
1764 | - property bool useTouchY |
1765 | - |
1766 | - onDraggingChanged: { |
1767 | - if (!dragging) { |
1768 | - if (slider.percent >= 0.85) { |
1769 | - root.hide(); |
1770 | - } else if (slider.percent >= 0.15) { |
1771 | - root.showError(); |
1772 | - } |
1773 | - } |
1774 | - |
1775 | - // We use a separate vars here rather than just directly looking at |
1776 | - // 'dragging' because we want to preserve our 'slider.offset' |
1777 | - // value during the above percent check. Now that we made it, |
1778 | - // we can have 'slider.offset' go back to zero. |
1779 | - offsetAnimation.enabled = !dragging; |
1780 | - useTouchY = dragging; |
1781 | - } |
1782 | - } |
1783 | -} |
1784 | |
1785 | === removed file 'qml/Tutorial/TutorialBottomFinish.qml' |
1786 | --- qml/Tutorial/TutorialBottomFinish.qml 2015-07-15 15:07:19 +0000 |
1787 | +++ qml/Tutorial/TutorialBottomFinish.qml 1970-01-01 00:00:00 +0000 |
1788 | @@ -1,41 +0,0 @@ |
1789 | -/* |
1790 | - * Copyright (C) 2014 Canonical, Ltd. |
1791 | - * |
1792 | - * This program is free software; you can redistribute it and/or modify |
1793 | - * it under the terms of the GNU General Public License as published by |
1794 | - * the Free Software Foundation; version 3. |
1795 | - * |
1796 | - * This program is distributed in the hope that it will be useful, |
1797 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1798 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1799 | - * GNU General Public License for more details. |
1800 | - * |
1801 | - * You should have received a copy of the GNU General Public License |
1802 | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1803 | - */ |
1804 | - |
1805 | -import QtQuick 2.4 |
1806 | -import Ubuntu.Components 1.3 |
1807 | -import "." as LocalComponents |
1808 | - |
1809 | -TutorialPage { |
1810 | - id: root |
1811 | - |
1812 | - title: i18n.tr("This action does different things for different apps") |
1813 | - text: i18n.tr("Tap here to finish.") |
1814 | - fullTextWidth: true |
1815 | - |
1816 | - foreground { |
1817 | - children: [ |
1818 | - LocalComponents.Tick { |
1819 | - objectName: "tick" |
1820 | - anchors { |
1821 | - horizontalCenter: parent.horizontalCenter |
1822 | - top: parent.top |
1823 | - topMargin: root.textBottom + units.gu(3) |
1824 | - } |
1825 | - onClicked: root.hide() |
1826 | - } |
1827 | - ] |
1828 | - } |
1829 | -} |
1830 | |
1831 | === modified file 'qml/Tutorial/TutorialContent.qml' |
1832 | --- qml/Tutorial/TutorialContent.qml 2015-08-25 07:25:26 +0000 |
1833 | +++ qml/Tutorial/TutorialContent.qml 2016-03-15 20:13:37 +0000 |
1834 | @@ -16,103 +16,273 @@ |
1835 | |
1836 | import QtQuick 2.4 |
1837 | import Ubuntu.Components 1.3 |
1838 | +import AccountsService 0.1 |
1839 | +import Unity.Application 0.1 |
1840 | |
1841 | Item { |
1842 | id: root |
1843 | |
1844 | property Item launcher |
1845 | property Item panel |
1846 | - |
1847 | - readonly property bool launcherEnabled: !running || |
1848 | - (!paused && tutorialLeft.shown) |
1849 | - readonly property bool spreadEnabled: !running |
1850 | - readonly property bool panelEnabled: !running |
1851 | - readonly property bool panelContentEnabled: !running |
1852 | - readonly property alias running: d.running |
1853 | - |
1854 | - property bool paused: false |
1855 | - property real edgeSize |
1856 | + property Item stage |
1857 | + property string usageScenario |
1858 | + property bool paused |
1859 | + property bool keyboardVisible |
1860 | + property var lastInputTimestamp |
1861 | + |
1862 | + readonly property bool launcherEnabled: !running |
1863 | + || tutorialLeftLoader.shown |
1864 | + || tutorialLeftLongLoader.shown |
1865 | + readonly property bool spreadEnabled: !running || tutorialRightLoader.shown |
1866 | + readonly property bool panelEnabled: !running || tutorialTopLoader.shown |
1867 | + readonly property bool running: tutorialLeftLoader.shown |
1868 | + || tutorialTopLoader.shown |
1869 | + || tutorialRightLoader.shown |
1870 | + || tutorialBottomLoader.shown |
1871 | |
1872 | signal finished() |
1873 | |
1874 | function finish() { |
1875 | - d.stop(); |
1876 | finished(); |
1877 | } |
1878 | |
1879 | //// |
1880 | |
1881 | - Component.onCompleted: { |
1882 | - d.start(); |
1883 | - } |
1884 | - |
1885 | QtObject { |
1886 | id: d |
1887 | |
1888 | - property bool running |
1889 | - |
1890 | - function stop() { |
1891 | - running = false; |
1892 | - } |
1893 | - |
1894 | - function start() { |
1895 | - running = true; |
1896 | - tutorialLeft.show(); |
1897 | - } |
1898 | - } |
1899 | - |
1900 | - TutorialLeft { |
1901 | - id: tutorialLeft |
1902 | - objectName: "tutorialLeft" |
1903 | - anchors.fill: parent |
1904 | - launcher: root.launcher |
1905 | - paused: !shown || root.paused |
1906 | - |
1907 | - onFinished: tutorialLeftFinish.show() |
1908 | - } |
1909 | - |
1910 | - TutorialLeftFinish { |
1911 | - id: tutorialLeftFinish |
1912 | - objectName: "tutorialLeftFinish" |
1913 | - anchors.fill: parent |
1914 | - textXOffset: root.launcher.panelWidth |
1915 | - paused: !shown || root.paused |
1916 | - text: i18n.tr("Tap here to continue.") |
1917 | - |
1918 | - onFinished: { |
1919 | - root.launcher.hide(); |
1920 | - tutorialRight.show(); |
1921 | - } |
1922 | - } |
1923 | - |
1924 | - TutorialRight { |
1925 | - id: tutorialRight |
1926 | - objectName: "tutorialRight" |
1927 | - anchors.fill: parent |
1928 | - edgeSize: root.edgeSize |
1929 | - panel: root.panel |
1930 | - paused: !shown || root.paused |
1931 | - |
1932 | - onFinished: tutorialBottom.show() |
1933 | - } |
1934 | - |
1935 | - TutorialBottom { |
1936 | - id: tutorialBottom |
1937 | - objectName: "tutorialBottom" |
1938 | - anchors.fill: parent |
1939 | - edgeSize: root.edgeSize |
1940 | - paused: !shown || root.paused |
1941 | - |
1942 | - onFinished: tutorialBottomFinish.show() |
1943 | - } |
1944 | - |
1945 | - TutorialBottomFinish { |
1946 | - id: tutorialBottomFinish |
1947 | - objectName: "tutorialBottomFinish" |
1948 | - anchors.fill: parent |
1949 | - backgroundFadesOut: true |
1950 | - paused: !shown || root.paused |
1951 | - |
1952 | - onFinished: root.finish() |
1953 | + // We allow "" because it is briefly empty on startup, and we don't |
1954 | + // want to improperly skip any mobile tutorials. |
1955 | + property bool mobileScenario: root.usageScenario === "" || |
1956 | + root.usageScenario === "phone" || |
1957 | + root.usageScenario === "tablet" |
1958 | + |
1959 | + property var focusedApp: ApplicationManager.focusedApplicationId |
1960 | + ? ApplicationManager.findApplication(ApplicationManager.focusedApplicationId) |
1961 | + : null |
1962 | + |
1963 | + function haveShown(tutorialId) { |
1964 | + return AccountsService.demoEdgesCompleted.indexOf(tutorialId) != -1; |
1965 | + } |
1966 | + |
1967 | + property bool endPointsFinished: tutorialRightLoader.skipped && |
1968 | + tutorialBottomLoader.skipped |
1969 | + onEndPointsFinishedChanged: if (endPointsFinished) root.finish() |
1970 | + } |
1971 | + |
1972 | + Loader { |
1973 | + id: tutorialLeftLoader |
1974 | + objectName: "tutorialLeftLoader" |
1975 | + anchors.fill: parent |
1976 | + |
1977 | + readonly property bool skipped: !d.mobileScenario || d.haveShown("left") |
1978 | + readonly property bool shown: item && item.shown |
1979 | + active: !skipped || (item && item.visible) |
1980 | + onSkippedChanged: if (skipped && shown) item.hide() |
1981 | + |
1982 | + sourceComponent: TutorialLeft { |
1983 | + id: tutorialLeft |
1984 | + objectName: "tutorialLeft" |
1985 | + anchors.fill: parent |
1986 | + launcher: root.launcher |
1987 | + hides: [launcher, panel.indicators] |
1988 | + paused: root.paused |
1989 | + |
1990 | + isReady: !tutorialLeftLoader.skipped && !paused && !keyboardVisible |
1991 | + |
1992 | + // Use an idle timer here, because when constructed, all our isReady variables will be false. |
1993 | + // Qml needs a moment to copy their values from Tutorial.qml. So we idle it and recheck. |
1994 | + Timer { |
1995 | + id: tutorialLeftTimer |
1996 | + interval: 0 |
1997 | + onTriggered: if (tutorialLeft.isReady && !tutorialLeft.shown) tutorialLeft.show() |
1998 | + } |
1999 | + |
2000 | + onIsReadyChanged: if (isReady && !shown) tutorialLeftTimer.start() |
2001 | + onFinished: AccountsService.markDemoEdgeCompleted("left") |
2002 | + } |
2003 | + } |
2004 | + |
2005 | + Loader { |
2006 | + id: tutorialLeftLongLoader |
2007 | + objectName: "tutorialLeftLongLoader" |
2008 | + anchors.fill: parent |
2009 | + |
2010 | + readonly property bool skipped: !d.mobileScenario || d.haveShown("left-long") |
2011 | + readonly property bool shown: item && item.shown |
2012 | + active: !skipped || (item && item.visible) |
2013 | + onSkippedChanged: if (skipped && shown) item.hide() |
2014 | + |
2015 | + sourceComponent: TutorialLeftLong { |
2016 | + id: tutorialLeftLong |
2017 | + objectName: "tutorialLeftLong" |
2018 | + anchors.fill: parent |
2019 | + launcher: root.launcher |
2020 | + hides: [launcher, panel.indicators] |
2021 | + paused: root.paused |
2022 | + |
2023 | + skipped: tutorialLeftLongLoader.skipped |
2024 | + isReady: tutorialLeftLoader.skipped && !skipped && !paused && !keyboardVisible && |
2025 | + !tutorialBottomLoader.shown && !tutorialBottomLoader.mightShow |
2026 | + |
2027 | + Timer { |
2028 | + id: tutorialLeftLongTimer |
2029 | + objectName: "tutorialLeftLongTimer" |
2030 | + interval: 5000 |
2031 | + onTriggered: { |
2032 | + if (parent.isReady) { |
2033 | + if (!parent.shown) { |
2034 | + parent.show(); |
2035 | + } |
2036 | + } else if (!parent.skipped) { |
2037 | + restart(); |
2038 | + } |
2039 | + } |
2040 | + } |
2041 | + |
2042 | + onIsReadyChanged: if (isReady && !shown) tutorialLeftLongTimer.start() |
2043 | + onFinished: AccountsService.markDemoEdgeCompleted("left-long") |
2044 | + } |
2045 | + } |
2046 | + |
2047 | + Loader { |
2048 | + id: tutorialTopLoader |
2049 | + objectName: "tutorialTopLoader" |
2050 | + anchors.fill: parent |
2051 | + |
2052 | + readonly property bool skipped: !d.mobileScenario || d.haveShown("top") |
2053 | + readonly property bool shown: item && item.shown |
2054 | + active: !skipped || (item && item.visible) |
2055 | + onSkippedChanged: if (skipped && shown) item.hide() |
2056 | + |
2057 | + sourceComponent: TutorialTop { |
2058 | + id: tutorialTop |
2059 | + objectName: "tutorialTop" |
2060 | + anchors.fill: parent |
2061 | + panel: root.panel |
2062 | + hides: [launcher, panel.indicators] |
2063 | + paused: root.paused |
2064 | + |
2065 | + skipped: tutorialTopLoader.skipped |
2066 | + isReady: tutorialLeftLongLoader.skipped && !skipped && !paused && !keyboardVisible && |
2067 | + !tutorialBottomLoader.shown && !tutorialBottomLoader.mightShow |
2068 | + |
2069 | + // We fire 30s after left edge tutorial, with at least 3s of inactivity |
2070 | + |
2071 | + InactivityTimer { |
2072 | + id: tutorialTopInactivityTimer |
2073 | + lastInputTimestamp: root.lastInputTimestamp |
2074 | + page: parent |
2075 | + } |
2076 | + |
2077 | + Timer { |
2078 | + id: tutorialTopTimer |
2079 | + objectName: "tutorialTopTimer" |
2080 | + interval: 27000 |
2081 | + onTriggered: tutorialTopInactivityTimer.start() |
2082 | + } |
2083 | + |
2084 | + onIsReadyChanged: if (isReady && !shown) tutorialTopTimer.start() |
2085 | + onFinished: AccountsService.markDemoEdgeCompleted("top") |
2086 | + } |
2087 | + } |
2088 | + |
2089 | + Loader { |
2090 | + id: tutorialRightLoader |
2091 | + objectName: "tutorialRightLoader" |
2092 | + anchors.fill: parent |
2093 | + |
2094 | + readonly property bool skipped: d.haveShown("right") |
2095 | + readonly property bool shown: item && item.shown |
2096 | + active: !skipped || (item && item.visible) |
2097 | + onSkippedChanged: if (skipped && shown) item.hide() |
2098 | + |
2099 | + sourceComponent: TutorialRight { |
2100 | + id: tutorialRight |
2101 | + objectName: "tutorialRight" |
2102 | + anchors.fill: parent |
2103 | + stage: root.stage |
2104 | + usageScenario: root.usageScenario |
2105 | + hides: [launcher, panel.indicators] |
2106 | + paused: root.paused |
2107 | + |
2108 | + skipped: tutorialRightLoader.skipped |
2109 | + isReady: tutorialTopLoader.skipped && !skipped && !paused && !keyboardVisible && |
2110 | + !tutorialBottomLoader.shown && !tutorialBottomLoader.mightShow && |
2111 | + ApplicationManager.count >= 3 |
2112 | + |
2113 | + InactivityTimer { |
2114 | + id: tutorialRightInactivityTimer |
2115 | + objectName: "tutorialRightInactivityTimer" |
2116 | + lastInputTimestamp: root.lastInputTimestamp |
2117 | + page: parent |
2118 | + } |
2119 | + |
2120 | + Connections { |
2121 | + target: d |
2122 | + onFocusedAppChanged: { |
2123 | + if (tutorialRight.isReady && !tutorialRight.shown && d.focusedApp |
2124 | + && d.focusedApp.state === ApplicationInfoInterface.Starting) { |
2125 | + tutorialRight.show(); |
2126 | + } |
2127 | + } |
2128 | + } |
2129 | + |
2130 | + onIsReadyChanged: if (isReady && !shown) tutorialRightInactivityTimer.start() |
2131 | + onFinished: AccountsService.markDemoEdgeCompleted("right") |
2132 | + } |
2133 | + } |
2134 | + |
2135 | + Loader { |
2136 | + id: tutorialBottomLoader |
2137 | + objectName: "tutorialBottomLoader" |
2138 | + anchors.fill: parent |
2139 | + |
2140 | + // See TutorialBottom.qml for an explanation of why we only support |
2141 | + // certain apps. |
2142 | + readonly property var supportedApps: ["address-book-app", |
2143 | + "com.ubuntu.calculator_calculator", |
2144 | + "dialer-app", |
2145 | + "messaging-app"] |
2146 | + readonly property bool skipped: { |
2147 | + if (!d.mobileScenario) { |
2148 | + return true; |
2149 | + } |
2150 | + for (var i = 0; i < supportedApps.length; i++) { |
2151 | + if (!d.haveShown("bottom-" + supportedApps[i])) { |
2152 | + return false; |
2153 | + } |
2154 | + } |
2155 | + return true; |
2156 | + } |
2157 | + readonly property bool shown: item && item.shown |
2158 | + readonly property bool haveShownFocusedApp: d.focusedApp && |
2159 | + d.haveShown("bottom-" + d.focusedApp.appId) |
2160 | + readonly property bool mightShow: !skipped && d.focusedApp && |
2161 | + supportedApps.indexOf(d.focusedApp.appId) !== -1 && |
2162 | + !haveShownFocusedApp |
2163 | + active: !skipped || (item && item.visible) |
2164 | + onHaveShownFocusedAppChanged: if (haveShownFocusedApp && shown) hide() |
2165 | + onSkippedChanged: if (skipped && shown) item.hide() |
2166 | + |
2167 | + sourceComponent: TutorialBottom { |
2168 | + id: tutorialBottom |
2169 | + objectName: "tutorialBottom" |
2170 | + anchors.fill: parent |
2171 | + hides: [launcher, panel.indicators] |
2172 | + paused: root.paused |
2173 | + usageScenario: root.usageScenario |
2174 | + stage: root.stage |
2175 | + application: d.focusedApp |
2176 | + |
2177 | + skipped: tutorialBottomLoader.skipped |
2178 | + isReady: !tutorialBottomLoader.skipped && !paused && !keyboardVisible && |
2179 | + !tutorialTopLoader.shown && !tutorialRightLoader.shown && |
2180 | + tutorialBottomLoader.mightShow && |
2181 | + d.focusedApp.state === ApplicationInfoInterface.Running |
2182 | + |
2183 | + onIsReadyChanged: if (isReady && !shown) show() |
2184 | + onFinished: AccountsService.markDemoEdgeCompleted("bottom-" + d.focusedApp.appId) |
2185 | + } |
2186 | } |
2187 | } |
2188 | |
2189 | === modified file 'qml/Tutorial/TutorialLeft.qml' |
2190 | --- qml/Tutorial/TutorialLeft.qml 2015-07-21 14:38:35 +0000 |
2191 | +++ qml/Tutorial/TutorialLeft.qml 2016-03-15 20:13:37 +0000 |
2192 | @@ -1,5 +1,5 @@ |
2193 | /* |
2194 | - * Copyright (C) 2014,2015 Canonical, Ltd. |
2195 | + * Copyright (C) 2015 Canonical, Ltd. |
2196 | * |
2197 | * This program is free software; you can redistribute it and/or modify |
2198 | * it under the terms of the GNU General Public License as published by |
2199 | @@ -23,79 +23,32 @@ |
2200 | |
2201 | property var launcher |
2202 | |
2203 | - title: i18n.tr("Open the launcher") |
2204 | - text: i18n.tr("Short swipe from the left edge.") |
2205 | - |
2206 | - textXOffset: root.launcher.x + root.launcher.visibleWidth |
2207 | - |
2208 | - Connections { |
2209 | - target: root.launcher |
2210 | - |
2211 | - onStateChanged: { |
2212 | - if (root.launcher.state === "visible") { |
2213 | - finishTimer.start(); |
2214 | - } |
2215 | - } |
2216 | - |
2217 | - onDash: { |
2218 | - finishTimer.stop(); |
2219 | - root.showError(); |
2220 | - root.launcher.hide(); |
2221 | - } |
2222 | - } |
2223 | - |
2224 | - SequentialAnimation { |
2225 | - id: teaseAnimation |
2226 | - objectName: "teaseAnimation" |
2227 | - paused: running && root.paused |
2228 | - running: !slider.active && root.launcher.visibleWidth === 0 && root.shown |
2229 | - loops: Animation.Infinite |
2230 | - property real bounce: 0 |
2231 | - readonly property real maxBounce: units.gu(2) |
2232 | - |
2233 | - UbuntuNumberAnimation { |
2234 | - target: teaseAnimation |
2235 | - property: "bounce" |
2236 | - to: teaseAnimation.maxBounce |
2237 | - duration: UbuntuAnimation.SleepyDuration |
2238 | - } |
2239 | - UbuntuNumberAnimation { |
2240 | - target: teaseAnimation |
2241 | - property: "bounce" |
2242 | - to: 0 |
2243 | - duration: UbuntuAnimation.SleepyDuration |
2244 | - } |
2245 | - } |
2246 | - |
2247 | - Binding { |
2248 | - target: root.launcher |
2249 | - when: root.shown |
2250 | - property: "x" |
2251 | - value: Math.min(root.launcher.panelWidth - root.launcher.visibleWidth, teaseAnimation.bounce) |
2252 | - } |
2253 | - |
2254 | - Timer { |
2255 | - id: finishTimer |
2256 | - interval: 1 |
2257 | - onTriggered: { |
2258 | - root.hide(); |
2259 | - root.launcher.x = 0; // make sure to reset launcher before we go |
2260 | - } |
2261 | - } |
2262 | - |
2263 | - foreground { |
2264 | - children: [ |
2265 | - LocalComponents.Slider { |
2266 | - id: slider |
2267 | - anchors { |
2268 | - left: parent.left |
2269 | - top: parent.top |
2270 | - topMargin: root.textBottom + units.gu(3) |
2271 | - } |
2272 | - offset: root.launcher.x + root.launcher.visibleWidth + root.launcher.progress |
2273 | - active: root.launcher.dragging |
2274 | - shortSwipe: true |
2275 | - } |
2276 | - ] |
2277 | + opacityOverride: 1 - launcher.visibleWidth / launcher.panelWidth |
2278 | + |
2279 | + mouseArea { |
2280 | + anchors.leftMargin: launcher.dragAreaWidth |
2281 | + } |
2282 | + |
2283 | + background { |
2284 | + sourceSize.height: 1916 |
2285 | + sourceSize.width: 1080 |
2286 | + source: Qt.resolvedUrl("graphics/background1.png") |
2287 | + mirror: true |
2288 | + } |
2289 | + |
2290 | + arrow { |
2291 | + anchors.left: root.left |
2292 | + anchors.leftMargin: units.gu(2) |
2293 | + anchors.verticalCenter: root.verticalCenter |
2294 | + rotation: 180 |
2295 | + } |
2296 | + |
2297 | + label { |
2298 | + text: i18n.tr("Swipe from the left edge to open the launcher") |
2299 | + anchors.left: arrow.right |
2300 | + anchors.leftMargin: units.gu(3) |
2301 | + anchors.right: root.right |
2302 | + anchors.rightMargin: units.gu(4) |
2303 | + anchors.verticalCenter: arrow.verticalCenter |
2304 | } |
2305 | } |
2306 | |
2307 | === removed file 'qml/Tutorial/TutorialLeftFinish.qml' |
2308 | --- qml/Tutorial/TutorialLeftFinish.qml 2015-07-15 15:07:19 +0000 |
2309 | +++ qml/Tutorial/TutorialLeftFinish.qml 1970-01-01 00:00:00 +0000 |
2310 | @@ -1,41 +0,0 @@ |
2311 | -/* |
2312 | - * Copyright (C) 2014 Canonical, Ltd. |
2313 | - * |
2314 | - * This program is free software; you can redistribute it and/or modify |
2315 | - * it under the terms of the GNU General Public License as published by |
2316 | - * the Free Software Foundation; version 3. |
2317 | - * |
2318 | - * This program is distributed in the hope that it will be useful, |
2319 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2320 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2321 | - * GNU General Public License for more details. |
2322 | - * |
2323 | - * You should have received a copy of the GNU General Public License |
2324 | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2325 | - */ |
2326 | - |
2327 | -import QtQuick 2.4 |
2328 | -import Ubuntu.Components 1.3 |
2329 | -import "." as LocalComponents |
2330 | - |
2331 | -TutorialPage { |
2332 | - id: root |
2333 | - |
2334 | - title: i18n.tr("These are the shortcuts to favorite apps") |
2335 | - text: i18n.tr("Tap here to continue.") |
2336 | - fullTextWidth: true |
2337 | - |
2338 | - foreground { |
2339 | - children: [ |
2340 | - LocalComponents.Tick { |
2341 | - objectName: "tick" |
2342 | - anchors { |
2343 | - horizontalCenter: parent.horizontalCenter |
2344 | - top: parent.top |
2345 | - topMargin: root.textBottom + units.gu(3) |
2346 | - } |
2347 | - onClicked: root.hide() |
2348 | - } |
2349 | - ] |
2350 | - } |
2351 | -} |
2352 | |
2353 | === added file 'qml/Tutorial/TutorialLeftLong.qml' |
2354 | --- qml/Tutorial/TutorialLeftLong.qml 1970-01-01 00:00:00 +0000 |
2355 | +++ qml/Tutorial/TutorialLeftLong.qml 2016-03-15 20:13:37 +0000 |
2356 | @@ -0,0 +1,54 @@ |
2357 | +/* |
2358 | + * Copyright (C) 2016 Canonical, Ltd. |
2359 | + * |
2360 | + * This program is free software; you can redistribute it and/or modify |
2361 | + * it under the terms of the GNU General Public License as published by |
2362 | + * the Free Software Foundation; version 3. |
2363 | + * |
2364 | + * This program is distributed in the hope that it will be useful, |
2365 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2366 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2367 | + * GNU General Public License for more details. |
2368 | + * |
2369 | + * You should have received a copy of the GNU General Public License |
2370 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2371 | + */ |
2372 | + |
2373 | +import QtQuick 2.4 |
2374 | +import Ubuntu.Components 1.3 |
2375 | +import "." as LocalComponents |
2376 | + |
2377 | +TutorialPage { |
2378 | + id: root |
2379 | + |
2380 | + property var launcher |
2381 | + |
2382 | + opacityOverride: 1 - launcher.dragDistance / launcher.minimizeDistance |
2383 | + |
2384 | + mouseArea { |
2385 | + anchors.leftMargin: launcher.dragAreaWidth |
2386 | + } |
2387 | + |
2388 | + background { |
2389 | + sourceSize.height: 1916 |
2390 | + sourceSize.width: 1080 |
2391 | + source: Qt.resolvedUrl("graphics/background1.png") |
2392 | + mirror: true |
2393 | + } |
2394 | + |
2395 | + arrow { |
2396 | + anchors.left: root.left |
2397 | + anchors.leftMargin: units.gu(2) |
2398 | + anchors.verticalCenter: root.verticalCenter |
2399 | + rotation: 180 |
2400 | + } |
2401 | + |
2402 | + label { |
2403 | + text: i18n.tr("Long swipe from the left edge to open the Today scope") |
2404 | + anchors.left: arrow.right |
2405 | + anchors.leftMargin: units.gu(3) |
2406 | + anchors.right: root.right |
2407 | + anchors.rightMargin: units.gu(4) |
2408 | + anchors.verticalCenter: arrow.verticalCenter |
2409 | + } |
2410 | +} |
2411 | |
2412 | === modified file 'qml/Tutorial/TutorialPage.qml' |
2413 | --- qml/Tutorial/TutorialPage.qml 2015-07-15 15:07:19 +0000 |
2414 | +++ qml/Tutorial/TutorialPage.qml 2016-03-15 20:13:37 +0000 |
2415 | @@ -21,225 +21,101 @@ |
2416 | Showable { |
2417 | id: root |
2418 | |
2419 | - // This is the header displayed, like "Right edge" |
2420 | - property alias title: titleLabel.text |
2421 | - |
2422 | - // This is the block of text displayed below the header |
2423 | - property alias text: textLabel.text |
2424 | - |
2425 | - // Whether animations are paused |
2426 | + property alias arrow: arrow |
2427 | + property alias label: label |
2428 | + property alias background: background |
2429 | + property alias mouseArea: mouseArea |
2430 | + property real opacityOverride: 1 |
2431 | property bool paused |
2432 | - |
2433 | - // Whether to give the text the full width that the title has |
2434 | - property bool fullTextWidth |
2435 | - |
2436 | - // Whether whole page (background + foreground) or just the foreground fades in |
2437 | - property bool backgroundFadesIn: false |
2438 | - |
2439 | - // Whether whole page (background + foreground) or just the foreground fades out |
2440 | - property bool backgroundFadesOut: false |
2441 | - |
2442 | - // The foreground Item, add children to it that you want to fade in |
2443 | - property alias foreground: foregroundExtra |
2444 | - |
2445 | - // The text label bottom, so you can position elements relative to it |
2446 | - readonly property real textBottom: Math.max(textLabel.y + textLabel.height, errorTextLabel.y + errorTextLabel.height) |
2447 | - |
2448 | - // The MouseArea that eats events (so you can adjust size as you will) |
2449 | - property alias mouseArea: mouseArea |
2450 | - |
2451 | - // X/Y offsets for text |
2452 | - property real textXOffset: 0 |
2453 | - property real textYOffset: 0 |
2454 | - |
2455 | - // Foreground text opacity |
2456 | - property real textOpacity: 1 |
2457 | + property bool skipped |
2458 | + property bool isReady |
2459 | |
2460 | signal finished() |
2461 | |
2462 | - function showError() { |
2463 | - errorTimer.start(); |
2464 | - } |
2465 | - |
2466 | //// |
2467 | |
2468 | + QtObject { |
2469 | + id: d |
2470 | + property bool showOnUnpause |
2471 | + } |
2472 | + |
2473 | visible: false |
2474 | shown: false |
2475 | |
2476 | - property real _foregroundHideOpacity |
2477 | + opacity: Math.max(Math.min(_showOpacity, opacityOverride), 0) |
2478 | + onOpacityOverrideChanged: { |
2479 | + if (opacityOverride <= 0) { |
2480 | + d.showOnUnpause = false; |
2481 | + hide(); |
2482 | + } |
2483 | + } |
2484 | + property real _showOpacity: 0 |
2485 | + |
2486 | + onPausedChanged: { |
2487 | + if (paused && shown) { |
2488 | + d.showOnUnpause = true; |
2489 | + hide(); |
2490 | + } else if (!paused && d.showOnUnpause) { |
2491 | + if (isReady) { |
2492 | + show(); |
2493 | + } else if (hideAnimation.running) { |
2494 | + hideAnimation.stop(); |
2495 | + } |
2496 | + d.showOnUnpause = false; |
2497 | + } |
2498 | + } |
2499 | |
2500 | showAnimation: StandardAnimation { |
2501 | - property: root.backgroundFadesIn ? "opacity" : "_foregroundHideOpacity" |
2502 | + property: "_showOpacity" |
2503 | from: 0 |
2504 | to: 1 |
2505 | - duration: root.backgroundFadesIn ? UbuntuAnimation.SleepyDuration : UbuntuAnimation.BriskDuration |
2506 | + duration: UbuntuAnimation.SleepyDuration |
2507 | onStarted: root.visible = true |
2508 | } |
2509 | |
2510 | hideAnimation: StandardAnimation { |
2511 | - property: root.backgroundFadesOut ? "opacity" : "_foregroundHideOpacity" |
2512 | + property: "_showOpacity" |
2513 | to: 0 |
2514 | duration: UbuntuAnimation.BriskDuration |
2515 | onStopped: { |
2516 | root.visible = false; |
2517 | - root.finished(); |
2518 | - } |
2519 | - } |
2520 | - |
2521 | - QtObject { |
2522 | - id: d |
2523 | - |
2524 | - readonly property real sideMargin: units.gu(5.5) |
2525 | - readonly property real verticalOffset: -units.gu(9) |
2526 | - readonly property real textXOffset: Math.max(0, root.textXOffset - sideMargin + units.gu(2)) |
2527 | - |
2528 | - property real fadeInOffset: { |
2529 | - if (showAnimation.running) { |
2530 | - var opacity = root[root.showAnimation.property] |
2531 | - return (1 - opacity) * units.gu(3); |
2532 | - } else { |
2533 | - return 0; |
2534 | + if (!d.showOnUnpause) { |
2535 | + root.finished(); |
2536 | } |
2537 | } |
2538 | } |
2539 | |
2540 | - Timer { |
2541 | - id: errorTimer |
2542 | - interval: 3500 |
2543 | - } |
2544 | - |
2545 | MouseArea { // eat any errant presses |
2546 | id: mouseArea |
2547 | anchors.fill: parent |
2548 | } |
2549 | |
2550 | - Rectangle { |
2551 | - anchors.fill: parent |
2552 | - color: "black" |
2553 | - opacity: 0.82 |
2554 | - } |
2555 | - |
2556 | - Item { |
2557 | - id: foreground |
2558 | - anchors.fill: parent |
2559 | - opacity: root._foregroundHideOpacity |
2560 | - |
2561 | - Item { |
2562 | - anchors.fill: parent |
2563 | - opacity: root.textOpacity |
2564 | - |
2565 | - Label { |
2566 | - id: titleLabel |
2567 | - anchors { |
2568 | - top: parent.verticalCenter |
2569 | - topMargin: d.verticalOffset + root.textYOffset |
2570 | - left: parent.left |
2571 | - leftMargin: d.sideMargin + d.textXOffset |
2572 | - } |
2573 | - width: parent.width - d.sideMargin * 2 |
2574 | - horizontalAlignment: Text.AlignLeft |
2575 | - wrapMode: Text.Wrap |
2576 | - font.weight: Font.Light |
2577 | - font.pixelSize: units.gu(3.5) |
2578 | - } |
2579 | - |
2580 | - Label { |
2581 | - id: textLabel |
2582 | - anchors { |
2583 | - top: titleLabel.bottom |
2584 | - topMargin: units.gu(2) |
2585 | - left: parent.left |
2586 | - leftMargin: d.sideMargin + d.textXOffset |
2587 | - } |
2588 | - width: (parent.width - d.sideMargin * 2) * (fullTextWidth ? 1 : 0.66) |
2589 | - horizontalAlignment: Text.AlignLeft |
2590 | - wrapMode: Text.Wrap |
2591 | - font.weight: Font.Light |
2592 | - font.pixelSize: units.gu(2.5) |
2593 | - } |
2594 | - |
2595 | - // We use two separate labels like this rather than just changing |
2596 | - // the text of the above labels because we want to know where to place |
2597 | - // sliders (via root.textBottom) without having that place change |
2598 | - // as the text changes length. |
2599 | - Label { |
2600 | - id: errorTitleLabel |
2601 | - objectName: "errorTitleLabel" |
2602 | - anchors { |
2603 | - top: titleLabel.top |
2604 | - left: titleLabel.left |
2605 | - } |
2606 | - width: titleLabel.width |
2607 | - horizontalAlignment: titleLabel.horizontalAlignment |
2608 | - wrapMode: titleLabel.wrapMode |
2609 | - font.weight: titleLabel.font.weight |
2610 | - font.pixelSize: titleLabel.font.pixelSize |
2611 | - opacity: 0 |
2612 | - text: i18n.tr("You almost got it!") |
2613 | - } |
2614 | - |
2615 | - Label { |
2616 | - id: errorTextLabel |
2617 | - objectName: "errorTextLabel" |
2618 | - anchors { |
2619 | - top: errorTitleLabel.bottom |
2620 | - topMargin: textLabel.anchors.topMargin |
2621 | - left: textLabel.left |
2622 | - } |
2623 | - width: textLabel.width |
2624 | - horizontalAlignment: textLabel.horizontalAlignment |
2625 | - wrapMode: textLabel.wrapMode |
2626 | - font.weight: textLabel.font.weight |
2627 | - font.pixelSize: textLabel.font.pixelSize |
2628 | - opacity: 0 |
2629 | - text: i18n.tr("Try again.") |
2630 | - } |
2631 | - } |
2632 | - |
2633 | - // A place for subclasses to add extra widgets |
2634 | - Item { |
2635 | - id: foregroundExtra |
2636 | - anchors.fill: parent |
2637 | - } |
2638 | - } |
2639 | - |
2640 | - states: State { |
2641 | - name: "errorState" |
2642 | - when: errorTimer.running |
2643 | - PropertyChanges { target: titleLabel; opacity: 0 } |
2644 | - PropertyChanges { target: textLabel; opacity: 0 } |
2645 | - PropertyChanges { target: errorTitleLabel; opacity: 1 } |
2646 | - PropertyChanges { target: errorTextLabel; opacity: 1 } |
2647 | - } |
2648 | - |
2649 | - transitions: Transition { |
2650 | - to: "errorState" |
2651 | - reversible: true |
2652 | - SequentialAnimation { |
2653 | - ParallelAnimation { |
2654 | - StandardAnimation { |
2655 | - target: titleLabel |
2656 | - property: "opacity" |
2657 | - duration: UbuntuAnimation.BriskDuration |
2658 | - } |
2659 | - StandardAnimation { |
2660 | - target: textLabel |
2661 | - property: "opacity" |
2662 | - duration: UbuntuAnimation.BriskDuration |
2663 | - } |
2664 | - } |
2665 | - ParallelAnimation { |
2666 | - StandardAnimation { |
2667 | - target: errorTitleLabel |
2668 | - property: "opacity" |
2669 | - duration: UbuntuAnimation.BriskDuration |
2670 | - } |
2671 | - StandardAnimation { |
2672 | - target: errorTextLabel |
2673 | - property: "opacity" |
2674 | - duration: UbuntuAnimation.BriskDuration |
2675 | - } |
2676 | - } |
2677 | - } |
2678 | + Image { |
2679 | + id: background |
2680 | + // Use x/y/height/width instead of anchors so that we don't adjust |
2681 | + // the image if the OSK appears. |
2682 | + x: 0 |
2683 | + y: 0 |
2684 | + height: root.height |
2685 | + width: root.width |
2686 | + fillMode: Image.PreserveAspectCrop |
2687 | + } |
2688 | + |
2689 | + Image { |
2690 | + id: arrow |
2691 | + width: units.gu(1.5) |
2692 | + source: Qt.resolvedUrl("graphics/arrow.svg") |
2693 | + fillMode: Image.PreserveAspectFit |
2694 | + mipmap: true |
2695 | + } |
2696 | + |
2697 | + Label { |
2698 | + id: label |
2699 | + objectName: "tutorialLabel" |
2700 | + fontSize: "large" |
2701 | + font.weight: Font.Light |
2702 | + color: "#333333" |
2703 | + wrapMode: Text.Wrap |
2704 | + lineHeight: 1.2 |
2705 | } |
2706 | } |
2707 | |
2708 | === added file 'qml/Tutorial/TutorialRight.qml' |
2709 | --- qml/Tutorial/TutorialRight.qml 1970-01-01 00:00:00 +0000 |
2710 | +++ qml/Tutorial/TutorialRight.qml 2016-03-15 20:13:37 +0000 |
2711 | @@ -0,0 +1,61 @@ |
2712 | +/* |
2713 | + * Copyright (C) 2015 Canonical, Ltd. |
2714 | + * |
2715 | + * This program is free software; you can redistribute it and/or modify |
2716 | + * it under the terms of the GNU General Public License as published by |
2717 | + * the Free Software Foundation; version 3. |
2718 | + * |
2719 | + * This program is distributed in the hope that it will be useful, |
2720 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2721 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2722 | + * GNU General Public License for more details. |
2723 | + * |
2724 | + * You should have received a copy of the GNU General Public License |
2725 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2726 | + */ |
2727 | + |
2728 | +import QtQuick 2.4 |
2729 | +import Ubuntu.Components 1.3 |
2730 | + |
2731 | +TutorialPage { |
2732 | + id: root |
2733 | + |
2734 | + property var stage |
2735 | + property string usageScenario |
2736 | + |
2737 | + // When on phone or tablet, fade out as the drag progresses |
2738 | + opacityOverride: usageScenario === "desktop" ? 1 : 1 - stage.dragProgress * 2 |
2739 | + |
2740 | + // Else on desktop, fade out when the spread is shown |
2741 | + Connections { |
2742 | + target: usageScenario === "desktop" ? stage : null |
2743 | + ignoreUnknownSignals: true |
2744 | + onSpreadShownChanged: if (stage.spreadShown && root.shown) root.hide() |
2745 | + } |
2746 | + |
2747 | + mouseArea { |
2748 | + anchors.rightMargin: stage.dragAreaWidth |
2749 | + } |
2750 | + |
2751 | + background { |
2752 | + sourceSize.height: 1916 |
2753 | + sourceSize.width: 1080 |
2754 | + source: Qt.resolvedUrl("graphics/background1.png") |
2755 | + } |
2756 | + |
2757 | + arrow { |
2758 | + anchors.right: root.right |
2759 | + anchors.rightMargin: units.gu(2) |
2760 | + anchors.verticalCenter: root.verticalCenter |
2761 | + } |
2762 | + |
2763 | + label { |
2764 | + text: root.usageScenario === "desktop" ? |
2765 | + i18n.tr("Hover your mouse on the right edge to view your open apps") : |
2766 | + i18n.tr("Short or long swipe from the right edge to view your open apps") |
2767 | + anchors.right: arrow.left |
2768 | + anchors.rightMargin: units.gu(2) - (label.width - label.contentWidth) |
2769 | + anchors.verticalCenter: arrow.verticalCenter |
2770 | + width: Math.min(units.gu(40), arrow.x - units.gu(4)) |
2771 | + } |
2772 | +} |
2773 | |
2774 | === removed file 'qml/Tutorial/TutorialRight.qml' |
2775 | --- qml/Tutorial/TutorialRight.qml 2015-07-15 15:07:19 +0000 |
2776 | +++ qml/Tutorial/TutorialRight.qml 1970-01-01 00:00:00 +0000 |
2777 | @@ -1,223 +0,0 @@ |
2778 | -/* |
2779 | - * Copyright (C) 2014 Canonical, Ltd. |
2780 | - * |
2781 | - * This program is free software; you can redistribute it and/or modify |
2782 | - * it under the terms of the GNU General Public License as published by |
2783 | - * the Free Software Foundation; version 3. |
2784 | - * |
2785 | - * This program is distributed in the hope that it will be useful, |
2786 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2787 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2788 | - * GNU General Public License for more details. |
2789 | - * |
2790 | - * You should have received a copy of the GNU General Public License |
2791 | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2792 | - */ |
2793 | - |
2794 | -import QtQuick 2.4 |
2795 | -import Ubuntu.Components 1.3 |
2796 | -import Ubuntu.Gestures 0.1 |
2797 | -import Unity.Application 0.1 |
2798 | -import "../Components" |
2799 | -import "../Stages" |
2800 | -import "." as LocalComponents |
2801 | - |
2802 | -TutorialPage { |
2803 | - id: root |
2804 | - |
2805 | - property var panel |
2806 | - property alias edgeSize: stage.dragAreaWidth |
2807 | - |
2808 | - title: i18n.tr("To view open apps") |
2809 | - text: i18n.tr("Long swipe from the right edge.") |
2810 | - |
2811 | - textOpacity: 1 - slider.percent |
2812 | - |
2813 | - SequentialAnimation { |
2814 | - id: teaseAnimation |
2815 | - paused: running && root.paused |
2816 | - running: !stage.dragging && stage.dragProgress === 0 |
2817 | - loops: Animation.Infinite |
2818 | - |
2819 | - UbuntuNumberAnimation { |
2820 | - target: stage |
2821 | - property: "x" |
2822 | - to: -units.gu(2) |
2823 | - duration: UbuntuAnimation.SleepyDuration |
2824 | - } |
2825 | - UbuntuNumberAnimation { |
2826 | - target: stage |
2827 | - property: "x" |
2828 | - to: 0 |
2829 | - duration: UbuntuAnimation.SleepyDuration |
2830 | - } |
2831 | - } |
2832 | - |
2833 | - foreground { |
2834 | - children: [ |
2835 | - LocalComponents.Slider { |
2836 | - id: slider |
2837 | - anchors { |
2838 | - right: parent.right |
2839 | - top: parent.top |
2840 | - topMargin: root.textBottom + units.gu(3) |
2841 | - } |
2842 | - rotation: 180 |
2843 | - offset: stage.dragProgress - stage.x |
2844 | - active: stage.dragging |
2845 | - }, |
2846 | - |
2847 | - // Just assume PhoneStage for now. The tablet version of the right-edge |
2848 | - // tutorial is still being spec'd by the design team. |
2849 | - PhoneStage { |
2850 | - id: stage |
2851 | - objectName: "stage" |
2852 | - anchors.top: parent.top |
2853 | - width: parent.width |
2854 | - height: parent.height |
2855 | - applicationManager: fakeAppManager |
2856 | - color: "transparent" |
2857 | - interactive: false |
2858 | - altTabEnabled: false |
2859 | - focusFirstApp: false |
2860 | - startScale: 0.8 |
2861 | - endScale: 0.6 |
2862 | - dragAreaOverlap: -x |
2863 | - |
2864 | - onOpened: { |
2865 | - overlay.show(); |
2866 | - root.textOpacity = 0; |
2867 | - slider.visible = false; |
2868 | - } |
2869 | - |
2870 | - onDraggingChanged: { |
2871 | - if (!dragging) { |
2872 | - if (!overlay.shown) { |
2873 | - root.showError(); |
2874 | - } |
2875 | - teaseAnimation.complete(); |
2876 | - } |
2877 | - } |
2878 | - }, |
2879 | - |
2880 | - Showable { |
2881 | - id: overlay |
2882 | - objectName: "overlay" |
2883 | - anchors.fill: parent |
2884 | - |
2885 | - opacity: 0 |
2886 | - shown: false |
2887 | - showAnimation: UbuntuNumberAnimation { property: "opacity"; to: 1 } |
2888 | - |
2889 | - Label { |
2890 | - anchors.top: parent.top |
2891 | - anchors.topMargin: root.panel.panelHeight + units.gu(2) |
2892 | - anchors.left: parent.left |
2893 | - anchors.leftMargin: units.gu(2) |
2894 | - anchors.right: parent.right |
2895 | - anchors.rightMargin: units.gu(2) |
2896 | - wrapMode: Text.Wrap |
2897 | - horizontalAlignment: Text.AlignHCenter |
2898 | - fontSize: "large" |
2899 | - text: i18n.tr("View all your running tasks.") |
2900 | - } |
2901 | - |
2902 | - LocalComponents.Tick { |
2903 | - objectName: "tick" |
2904 | - anchors.bottom: bottomOverlayText.top |
2905 | - anchors.bottomMargin: units.gu(1) |
2906 | - anchors.horizontalCenter: bottomOverlayText.horizontalCenter |
2907 | - onClicked: root.hide() |
2908 | - } |
2909 | - |
2910 | - Label { |
2911 | - id: bottomOverlayText |
2912 | - anchors.bottom: parent.bottom |
2913 | - anchors.bottomMargin: units.gu(2) |
2914 | - anchors.left: parent.left |
2915 | - anchors.leftMargin: units.gu(2) |
2916 | - anchors.right: parent.right |
2917 | - anchors.rightMargin: units.gu(2) |
2918 | - wrapMode: Text.Wrap |
2919 | - horizontalAlignment: Text.AlignHCenter |
2920 | - fontSize: "small" |
2921 | - text: i18n.tr("Tap here to continue.") |
2922 | - } |
2923 | - } |
2924 | - ] |
2925 | - } |
2926 | - |
2927 | - ListModel { |
2928 | - id: fakeAppManager |
2929 | - |
2930 | - readonly property string focusedApplicationId: "facebook" |
2931 | - |
2932 | - function focusApplication(appId) {} |
2933 | - function requestFocusApplication(appId) {} |
2934 | - function findApplication(appId) {return null;} |
2935 | - |
2936 | - signal applicationAdded(string appId) |
2937 | - signal applicationRemoved(string appId) |
2938 | - signal focusRequested(string appId) |
2939 | - |
2940 | - ListElement { |
2941 | - appId: "facebook" |
2942 | - fullscreen: false |
2943 | - name: "" |
2944 | - icon: "" |
2945 | - state: ApplicationInfoInterface.Stopped |
2946 | - splashTitle: "" |
2947 | - splashImage: "" |
2948 | - splashShowHeader: false |
2949 | - splashColor: "transparent" |
2950 | - splashColorHeader: "transparent" |
2951 | - splashColorFooter: "transparent" |
2952 | - defaultScreenshot: "../Tutorial/graphics/facebook.png" |
2953 | - } |
2954 | - |
2955 | - ListElement { |
2956 | - appId: "camera" |
2957 | - fullscreen: false |
2958 | - name: "" |
2959 | - icon: "" |
2960 | - state: ApplicationInfoInterface.Stopped |
2961 | - splashTitle: "" |
2962 | - splashImage: "" |
2963 | - splashShowHeader: false |
2964 | - splashColor: "transparent" |
2965 | - splashColorHeader: "transparent" |
2966 | - splashColorFooter: "transparent" |
2967 | - defaultScreenshot: "../Tutorial/graphics/camera.png" |
2968 | - } |
2969 | - |
2970 | - ListElement { |
2971 | - appId: "gallery" |
2972 | - fullscreen: false |
2973 | - name: "" |
2974 | - icon: "" |
2975 | - state: ApplicationInfoInterface.Stopped |
2976 | - splashTitle: "" |
2977 | - splashImage: "" |
2978 | - splashShowHeader: false |
2979 | - splashColor: "transparent" |
2980 | - splashColorHeader: "transparent" |
2981 | - splashColorFooter: "transparent" |
2982 | - defaultScreenshot: "../Tutorial/graphics/gallery.png" |
2983 | - } |
2984 | - |
2985 | - ListElement { |
2986 | - appId: "dialer" |
2987 | - fullscreen: false |
2988 | - name: "" |
2989 | - icon: "" |
2990 | - state: ApplicationInfoInterface.Stopped |
2991 | - splashTitle: "" |
2992 | - splashImage: "" |
2993 | - splashShowHeader: false |
2994 | - splashColor: "transparent" |
2995 | - splashColorHeader: "transparent" |
2996 | - splashColorFooter: "transparent" |
2997 | - defaultScreenshot: "../Tutorial/graphics/dialer.png" |
2998 | - } |
2999 | - } |
3000 | -} |
3001 | |
3002 | === added file 'qml/Tutorial/TutorialTop.qml' |
3003 | --- qml/Tutorial/TutorialTop.qml 1970-01-01 00:00:00 +0000 |
3004 | +++ qml/Tutorial/TutorialTop.qml 2016-03-15 20:13:37 +0000 |
3005 | @@ -0,0 +1,61 @@ |
3006 | +/* |
3007 | + * Copyright (C) 2015 Canonical, Ltd. |
3008 | + * |
3009 | + * This program is free software; you can redistribute it and/or modify |
3010 | + * it under the terms of the GNU General Public License as published by |
3011 | + * the Free Software Foundation; version 3. |
3012 | + * |
3013 | + * This program is distributed in the hope that it will be useful, |
3014 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
3015 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
3016 | + * GNU General Public License for more details. |
3017 | + * |
3018 | + * You should have received a copy of the GNU General Public License |
3019 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
3020 | + */ |
3021 | + |
3022 | +import QtQuick 2.4 |
3023 | +import Ubuntu.Components 1.3 |
3024 | +import "." as LocalComponents |
3025 | + |
3026 | +TutorialPage { |
3027 | + id: root |
3028 | + |
3029 | + property var panel |
3030 | + |
3031 | + opacityOverride: 1 - panel.indicators.unitProgress |
3032 | + |
3033 | + QtObject { |
3034 | + id: d |
3035 | + readonly property bool landscape: root.width > units.gu(50) |
3036 | + readonly property real columnWidth: landscape ? panel.indicators.width : root.width |
3037 | + } |
3038 | + |
3039 | + mouseArea { |
3040 | + anchors.topMargin: panel.indicators.minimizedPanelHeight |
3041 | + } |
3042 | + |
3043 | + background { |
3044 | + sourceSize.height: 1916 |
3045 | + sourceSize.width: 1080 |
3046 | + source: Qt.resolvedUrl("graphics/background2.png") |
3047 | + } |
3048 | + |
3049 | + arrow { |
3050 | + anchors.top: root.top |
3051 | + anchors.topMargin: units.gu(4) |
3052 | + anchors.horizontalCenter: root.right |
3053 | + anchors.horizontalCenterOffset: - d.columnWidth / 2 |
3054 | + rotation: -90 |
3055 | + } |
3056 | + |
3057 | + label { |
3058 | + text: d.landscape ? i18n.tr("Swipe from the top right edge to open the notification bar") |
3059 | + : i18n.tr("Swipe from the top edge to open the notification bar") |
3060 | + anchors.top: arrow.bottom |
3061 | + anchors.topMargin: units.gu(3) |
3062 | + anchors.horizontalCenter: arrow.horizontalCenter |
3063 | + anchors.horizontalCenterOffset: (label.width - label.contentWidth) / 2 |
3064 | + width: d.columnWidth - units.gu(8) |
3065 | + } |
3066 | +} |
3067 | |
3068 | === added file 'qml/Tutorial/graphics/arrow.svg' |
3069 | --- qml/Tutorial/graphics/arrow.svg 1970-01-01 00:00:00 +0000 |
3070 | +++ qml/Tutorial/graphics/arrow.svg 2016-03-15 20:13:37 +0000 |
3071 | @@ -0,0 +1,19 @@ |
3072 | +<?xml version="1.0" encoding="UTF-8" standalone="no"?> |
3073 | +<svg width="35px" height="106px" viewBox="0 0 35 106" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns"> |
3074 | + <!-- Generator: Sketch 3.3.3 (12072) - http://www.bohemiancoding.com/sketch --> |
3075 | + <title>left swipe arrow</title> |
3076 | + <desc>Created with Sketch.</desc> |
3077 | + <defs></defs> |
3078 | + <g id="Final-design" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage"> |
3079 | + <g id="1.Left-swipe" sketch:type="MSArtboardGroup" transform="translate(-54.000000, -906.000000)"> |
3080 | + <g id="left-swipe-arrow" sketch:type="MSLayerGroup" transform="translate(15.000000, 903.000000)"> |
3081 | + <g id="layer1" transform="translate(0.857146, 0.494959)" sketch:type="MSShapeGroup"> |
3082 | + <g id="g4216" transform="translate(0.952384, 0.831650)"> |
3083 | + <path d="M38.0127338,5.94292186 C40.8696258,9.70328846 43.6961579,13.5492607 46.4521869,17.5776877 C50.0756129,22.8738077 53.4767719,28.2917937 56.6611719,33.8315937 C60.6031619,40.9214757 64.3797399,47.5658927 67.7217189,54.6714377 C64.3797399,61.7769828 60.6031619,68.4213998 56.6611719,75.5112818 C53.4767719,81.0510808 50.0756129,86.4690678 46.4521869,91.7651878 C43.6961579,95.7936138 40.8696258,99.6395938 38.0127338,103.399951 L38.0127338,107.669481 C42.0030779,102.508161 45.9748129,97.3405748 49.5537499,92.0679218 C54.5609019,84.6937758 59.0395839,77.5443828 62.9990629,70.6226098 C66.5019159,64.4983168 69.0866949,59.3452977 71.2158589,54.6733907 L69.4678129,54.6713907 L71.2158589,54.6693907 C69.0866949,49.9975777 66.5019159,44.8445587 62.9990629,38.7202657 C59.0395839,31.7984927 54.5609019,24.6490997 49.5537499,17.2749527 C45.9748129,12.0022997 42.0030779,6.83471186 38.0127338,1.67339065 L38.0127338,5.94292186 Z" id="left-swipe-arrow" fill="#6C0D52" transform="translate(54.614296, 54.671436) scale(-1, 1) translate(-54.614296, -54.671436) "></path> |
3084 | + <rect id="rect4782-01" transform="translate(54.190469, 54.673389) rotate(90.000000) translate(-54.190469, -54.673389) " x="0.190470662" y="0.67339065" width="107.999997" height="107.999997"></rect> |
3085 | + </g> |
3086 | + </g> |
3087 | + </g> |
3088 | + </g> |
3089 | + </g> |
3090 | +</svg> |
3091 | \ No newline at end of file |
3092 | |
3093 | === added file 'qml/Tutorial/graphics/background1.png' |
3094 | Binary files qml/Tutorial/graphics/background1.png 1970-01-01 00:00:00 +0000 and qml/Tutorial/graphics/background1.png 2016-03-15 20:13:37 +0000 differ |
3095 | === added file 'qml/Tutorial/graphics/background2.png' |
3096 | Binary files qml/Tutorial/graphics/background2.png 1970-01-01 00:00:00 +0000 and qml/Tutorial/graphics/background2.png 2016-03-15 20:13:37 +0000 differ |
3097 | === removed file 'qml/Tutorial/graphics/camera.png' |
3098 | Binary files qml/Tutorial/graphics/camera.png 2015-01-09 21:56:17 +0000 and qml/Tutorial/graphics/camera.png 1970-01-01 00:00:00 +0000 differ |
3099 | === removed file 'qml/Tutorial/graphics/chevron.png' |
3100 | Binary files qml/Tutorial/graphics/chevron.png 2014-12-18 23:32:42 +0000 and qml/Tutorial/graphics/chevron.png 1970-01-01 00:00:00 +0000 differ |
3101 | === removed file 'qml/Tutorial/graphics/dialer.png' |
3102 | Binary files qml/Tutorial/graphics/dialer.png 2015-01-09 21:56:17 +0000 and qml/Tutorial/graphics/dialer.png 1970-01-01 00:00:00 +0000 differ |
3103 | === removed file 'qml/Tutorial/graphics/facebook.png' |
3104 | Binary files qml/Tutorial/graphics/facebook.png 2015-01-12 14:02:33 +0000 and qml/Tutorial/graphics/facebook.png 1970-01-01 00:00:00 +0000 differ |
3105 | === removed file 'qml/Tutorial/graphics/gallery.png' |
3106 | Binary files qml/Tutorial/graphics/gallery.png 2015-01-09 21:56:17 +0000 and qml/Tutorial/graphics/gallery.png 1970-01-01 00:00:00 +0000 differ |
3107 | === removed file 'qml/Tutorial/graphics/tick.png' |
3108 | Binary files qml/Tutorial/graphics/tick.png 2014-12-18 23:32:42 +0000 and qml/Tutorial/graphics/tick.png 1970-01-01 00:00:00 +0000 differ |
3109 | === modified file 'tests/autopilot/unity8/shell/emulators.py' |
3110 | --- tests/autopilot/unity8/shell/emulators.py 2015-04-29 19:21:18 +0000 |
3111 | +++ tests/autopilot/unity8/shell/emulators.py 2016-03-15 20:13:37 +0000 |
3112 | @@ -36,7 +36,6 @@ |
3113 | 'greeter', |
3114 | 'launcher', |
3115 | 'main_window', |
3116 | - 'tutorial', |
3117 | 'UnityEmulatorException', |
3118 | ] |
3119 | |
3120 | @@ -46,7 +45,6 @@ |
3121 | dash, |
3122 | launcher, |
3123 | shell as main_window, |
3124 | - tutorial, |
3125 | UnityException as UnityEmulatorException |
3126 | ) |
3127 | from unity8.shell import create_interactive_notification |
3128 | |
3129 | === removed file 'tests/autopilot/unity8/shell/tests/test_tutorial.py' |
3130 | --- tests/autopilot/unity8/shell/tests/test_tutorial.py 2015-04-29 19:21:18 +0000 |
3131 | +++ tests/autopilot/unity8/shell/tests/test_tutorial.py 1970-01-01 00:00:00 +0000 |
3132 | @@ -1,57 +0,0 @@ |
3133 | -# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- |
3134 | -# |
3135 | -# Unity Autopilot Test Suite |
3136 | -# Copyright (C) 2014, 2015 Canonical |
3137 | -# |
3138 | -# This program is free software: you can redistribute it and/or modify |
3139 | -# it under the terms of the GNU General Public License as published by |
3140 | -# the Free Software Foundation, either version 3 of the License, or |
3141 | -# (at your option) any later version. |
3142 | -# |
3143 | -# This program is distributed in the hope that it will be useful, |
3144 | -# but WITHOUT ANY WARRANTY; without even the implied warranty of |
3145 | -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
3146 | -# GNU General Public License for more details. |
3147 | -# |
3148 | -# You should have received a copy of the GNU General Public License |
3149 | -# along with this program. If not, see <http://www.gnu.org/licenses/>. |
3150 | -# |
3151 | - |
3152 | -from autopilot.matchers import Eventually |
3153 | -from testtools.matchers import Equals |
3154 | - |
3155 | -from unity8.shell import ( |
3156 | - fixture_setup, |
3157 | - tests |
3158 | -) |
3159 | -# unused import to load the tutorial helpers custom proxy objects. |
3160 | -from unity8 import tutorial as tutorial_helpers # NOQA |
3161 | - |
3162 | - |
3163 | -class TutorialTestCase(tests.UnityTestCase): |
3164 | - |
3165 | - def setUp(self): |
3166 | - super().setUp() |
3167 | - self._qml_mock_enabled = False |
3168 | - self._data_dirs_mock_enabled = False |
3169 | - |
3170 | - self.useFixture(fixture_setup.Tutorial(True)) |
3171 | - self.unity = self.launch_unity() |
3172 | - |
3173 | - def test_complete_tutorial(self): |
3174 | - greeter = self.main_window.get_greeter() |
3175 | - tutorial = self.unity.select_single('Tutorial') |
3176 | - self.assertThat(tutorial.running, Eventually(Equals(True))) |
3177 | - greeter.swipe() |
3178 | - page = self.unity.wait_select_single(objectName='tutorialLeft') |
3179 | - page.short_swipe_right() |
3180 | - page = self.unity.wait_select_single(objectName='tutorialLeftFinish') |
3181 | - page.tap() |
3182 | - page = self.unity.wait_select_single(objectName='tutorialRight') |
3183 | - page.swipe_left() |
3184 | - page.tap() |
3185 | - page = self.unity.wait_select_single(objectName='tutorialBottom') |
3186 | - page.swipe_up() |
3187 | - page = self.unity.wait_select_single(objectName='tutorialBottomFinish') |
3188 | - page.tap() |
3189 | - self.assertThat(tutorial.running, Eventually(Equals(False))) |
3190 | |
3191 | === removed file 'tests/autopilot/unity8/tutorial.py' |
3192 | --- tests/autopilot/unity8/tutorial.py 2015-04-29 19:21:18 +0000 |
3193 | +++ tests/autopilot/unity8/tutorial.py 1970-01-01 00:00:00 +0000 |
3194 | @@ -1,73 +0,0 @@ |
3195 | -# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- |
3196 | -# |
3197 | -# Unity Autopilot Test Suite |
3198 | -# Copyright (C) 2014 Canonical |
3199 | -# |
3200 | -# This program is free software: you can redistribute it and/or modify |
3201 | -# it under the terms of the GNU General Public License as published by |
3202 | -# the Free Software Foundation, either version 3 of the License, or |
3203 | -# (at your option) any later version. |
3204 | -# |
3205 | -# This program is distributed in the hope that it will be useful, |
3206 | -# but WITHOUT ANY WARRANTY; without even the implied warranty of |
3207 | -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
3208 | -# GNU General Public License for more details. |
3209 | -# |
3210 | -# You should have received a copy of the GNU General Public License |
3211 | -# along with this program. If not, see <http://www.gnu.org/licenses/>. |
3212 | -# |
3213 | - |
3214 | -import logging |
3215 | - |
3216 | -import ubuntuuitoolkit |
3217 | - |
3218 | -import autopilot |
3219 | -from autopilot import introspection |
3220 | - |
3221 | - |
3222 | -logger = logging.getLogger(__name__) |
3223 | - |
3224 | - |
3225 | -class TutorialPage( |
3226 | - ubuntuuitoolkit.UbuntuUIToolkitCustomProxyObjectBase): |
3227 | - |
3228 | - @classmethod |
3229 | - def validate_dbus_object(cls, path, state): |
3230 | - name = introspection.get_classname_from_path(path) |
3231 | - return name in (b'TutorialPage', b'TutorialLeft', |
3232 | - b'TutorialLeftFinish', b'TutorialRight', |
3233 | - b'TutorialBottom', b'TutorialBottomFinish') |
3234 | - |
3235 | - @autopilot.logging.log_action(logger.info) |
3236 | - def short_swipe_right(self): |
3237 | - self.shown.wait_for(True) |
3238 | - x, y, width, height = self.globalRect |
3239 | - start_x = x |
3240 | - stop_x = x + width // 3 |
3241 | - start_y = stop_y = y + height // 2 |
3242 | - self.pointing_device.drag(start_x, start_y, stop_x, stop_y) |
3243 | - |
3244 | - @autopilot.logging.log_action(logger.info) |
3245 | - def swipe_left(self): |
3246 | - self.shown.wait_for(True) |
3247 | - x, y, width, height = self.globalRect |
3248 | - start_x = width |
3249 | - stop_x = x |
3250 | - start_y = stop_y = y + height // 2 |
3251 | - self.pointing_device.drag(start_x, start_y, stop_x, stop_y) |
3252 | - |
3253 | - @autopilot.logging.log_action(logger.info) |
3254 | - def swipe_up(self): |
3255 | - self.shown.wait_for(True) |
3256 | - x, y, width, height = self.globalRect |
3257 | - start_y = height |
3258 | - stop_y = y |
3259 | - start_x = stop_x = x + width // 2 |
3260 | - self.pointing_device.drag(start_x, start_y, stop_x, stop_y) |
3261 | - |
3262 | - @autopilot.logging.log_action(logger.info) |
3263 | - def tap(self): |
3264 | - """Tap the tick button to complete this step.""" |
3265 | - self.shown.wait_for(True) |
3266 | - button = self.wait_select_single(objectName="tick") |
3267 | - self.pointing_device.click_object(button) |
3268 | |
3269 | === modified file 'tests/mocks/AccountsService/AccountsService.cpp' |
3270 | --- tests/mocks/AccountsService/AccountsService.cpp 2016-03-15 20:13:36 +0000 |
3271 | +++ tests/mocks/AccountsService/AccountsService.cpp 2016-03-15 20:13:37 +0000 |
3272 | @@ -26,6 +26,7 @@ |
3273 | m_statsWelcomeScreen(true), |
3274 | m_failedLogins(0), |
3275 | m_demoEdges(false), |
3276 | + m_demoEdgesCompleted(), |
3277 | m_hereEnabled(false), |
3278 | m_hereLicensePath("") |
3279 | { |
3280 | @@ -54,6 +55,25 @@ |
3281 | Q_EMIT demoEdgesChanged(); |
3282 | } |
3283 | |
3284 | +QStringList AccountsService::demoEdgesCompleted() const |
3285 | +{ |
3286 | + return m_demoEdgesCompleted; |
3287 | +} |
3288 | + |
3289 | +void AccountsService::markDemoEdgeCompleted(const QString &edge) |
3290 | +{ |
3291 | + if (!m_demoEdgesCompleted.contains(edge)) { |
3292 | + m_demoEdgesCompleted << edge; |
3293 | + Q_EMIT demoEdgesCompletedChanged(); |
3294 | + } |
3295 | +} |
3296 | + |
3297 | +void AccountsService::setDemoEdgesCompleted(const QStringList &demoEdgesCompleted) |
3298 | +{ |
3299 | + m_demoEdgesCompleted = demoEdgesCompleted; |
3300 | + Q_EMIT demoEdgesCompletedChanged(); |
3301 | +} |
3302 | + |
3303 | bool AccountsService::enableLauncherWhileLocked() const |
3304 | { |
3305 | return m_enableLauncherWhileLocked; |
3306 | |
3307 | === modified file 'tests/mocks/AccountsService/AccountsService.h' |
3308 | --- tests/mocks/AccountsService/AccountsService.h 2016-03-15 20:13:36 +0000 |
3309 | +++ tests/mocks/AccountsService/AccountsService.h 2016-03-15 20:13:37 +0000 |
3310 | @@ -19,6 +19,7 @@ |
3311 | |
3312 | #include <QObject> |
3313 | #include <QString> |
3314 | +#include <QStringList> |
3315 | #include <QVariant> |
3316 | |
3317 | class AccountsService: public QObject |
3318 | @@ -33,6 +34,10 @@ |
3319 | READ demoEdges |
3320 | WRITE setDemoEdges |
3321 | NOTIFY demoEdgesChanged) |
3322 | + Q_PROPERTY (QStringList demoEdgesCompleted |
3323 | + READ demoEdgesCompleted |
3324 | + WRITE setDemoEdgesCompleted // only available in mock |
3325 | + NOTIFY demoEdgesCompletedChanged) |
3326 | Q_PROPERTY (bool enableLauncherWhileLocked |
3327 | READ enableLauncherWhileLocked |
3328 | WRITE setEnableLauncherWhileLocked // only available in mock |
3329 | @@ -82,6 +87,9 @@ |
3330 | void setUser(const QString &user); |
3331 | bool demoEdges() const; |
3332 | void setDemoEdges(bool demoEdges); |
3333 | + QStringList demoEdgesCompleted() const; |
3334 | + void setDemoEdgesCompleted(const QStringList &demoEdges); |
3335 | + Q_INVOKABLE void markDemoEdgeCompleted(const QString &edge); |
3336 | bool enableLauncherWhileLocked() const; |
3337 | void setEnableLauncherWhileLocked(bool enableLauncherWhileLocked); |
3338 | bool enableIndicatorsWhileLocked() const; |
3339 | @@ -106,6 +114,7 @@ |
3340 | Q_SIGNALS: |
3341 | void userChanged(); |
3342 | void demoEdgesChanged(); |
3343 | + void demoEdgesCompletedChanged(); |
3344 | void enableLauncherWhileLockedChanged(); |
3345 | void enableIndicatorsWhileLockedChanged(); |
3346 | void backgroundFileChanged(); |
3347 | @@ -125,6 +134,7 @@ |
3348 | bool m_statsWelcomeScreen; |
3349 | uint m_failedLogins; |
3350 | bool m_demoEdges; |
3351 | + QStringList m_demoEdgesCompleted; |
3352 | bool m_hereEnabled; |
3353 | QString m_hereLicensePath; |
3354 | QString m_realName; |
3355 | |
3356 | === modified file 'tests/mocks/AccountsService/AccountsService.qmltypes' |
3357 | --- tests/mocks/AccountsService/AccountsService.qmltypes 2015-02-13 09:01:16 +0000 |
3358 | +++ tests/mocks/AccountsService/AccountsService.qmltypes 2016-03-15 20:13:37 +0000 |
3359 | @@ -23,6 +23,7 @@ |
3360 | } |
3361 | Property { name: "user"; type: "string" } |
3362 | Property { name: "demoEdges"; type: "bool" } |
3363 | + Property { name: "demoEdgesCompleted"; type: "QStringList" } |
3364 | Property { name: "enableLauncherWhileLocked"; type: "bool" } |
3365 | Property { name: "enableIndicatorsWhileLocked"; type: "bool" } |
3366 | Property { name: "backgroundFile"; type: "string" } |
3367 | @@ -32,5 +33,9 @@ |
3368 | Property { name: "hereEnabled"; type: "bool" } |
3369 | Property { name: "hereLicensePath"; type: "string" } |
3370 | Property { name: "hereLicensePathValid"; type: "bool"; isReadonly: true } |
3371 | + Method { |
3372 | + name: "markDemoEdgeCompleted" |
3373 | + Parameter { name: "edge"; type: "string" } |
3374 | + } |
3375 | } |
3376 | } |
3377 | |
3378 | === modified file 'tests/mocks/Unity/Application/ApplicationInfo.cpp' |
3379 | --- tests/mocks/Unity/Application/ApplicationInfo.cpp 2016-01-22 19:44:56 +0000 |
3380 | +++ tests/mocks/Unity/Application/ApplicationInfo.cpp 2016-03-15 20:13:37 +0000 |
3381 | @@ -44,6 +44,7 @@ |
3382 | , m_isTouchApp(true) |
3383 | , m_exemptFromLifecycle(false) |
3384 | , m_manualSurfaceCreation(false) |
3385 | + , m_shellChrome(Mir::NormalChrome) |
3386 | { |
3387 | } |
3388 | |
3389 | @@ -63,6 +64,7 @@ |
3390 | , m_isTouchApp(true) |
3391 | , m_exemptFromLifecycle(false) |
3392 | , m_manualSurfaceCreation(false) |
3393 | + , m_shellChrome(Mir::NormalChrome) |
3394 | { |
3395 | } |
3396 | |
3397 | @@ -102,9 +104,11 @@ |
3398 | if (m_session) { |
3399 | m_session->setApplication(this); |
3400 | m_session->setParent(this); |
3401 | + m_session->setFullscreen(m_fullscreen); |
3402 | SessionManager::singleton()->registerSession(m_session); |
3403 | connect(m_session, &Session::surfaceAdded, |
3404 | this, &ApplicationInfo::onSessionSurfaceAdded); |
3405 | + connect(m_session, &Session::fullscreenChanged, this, &ApplicationInfo::fullscreenChanged); |
3406 | |
3407 | if (!m_manualSurfaceCreation) { |
3408 | QTimer::singleShot(500, m_session, &Session::createSurface); |
3409 | @@ -191,12 +195,17 @@ |
3410 | |
3411 | void ApplicationInfo::setFullscreen(bool value) |
3412 | { |
3413 | - if (value != m_fullscreen) { |
3414 | - m_fullscreen = value; |
3415 | - Q_EMIT fullscreenChanged(value); |
3416 | + m_fullscreen = value; |
3417 | + if (m_session) { |
3418 | + m_session->setFullscreen(value); |
3419 | } |
3420 | } |
3421 | |
3422 | +bool ApplicationInfo::fullscreen() const |
3423 | +{ |
3424 | + return m_session ? m_session->fullscreen() : false; |
3425 | +} |
3426 | + |
3427 | void ApplicationInfo::setManualSurfaceCreation(bool value) |
3428 | { |
3429 | if (value != m_manualSurfaceCreation) { |
3430 | @@ -262,6 +271,7 @@ |
3431 | } else { |
3432 | setState(Suspended); |
3433 | } |
3434 | + surface->setShellChrome(m_shellChrome); |
3435 | } |
3436 | } |
3437 | |
3438 | @@ -291,3 +301,11 @@ |
3439 | Q_EMIT initialSurfaceSizeChanged(m_initialSurfaceSize); |
3440 | } |
3441 | } |
3442 | + |
3443 | +void ApplicationInfo::setShellChrome(Mir::ShellChrome shellChrome) |
3444 | +{ |
3445 | + m_shellChrome = shellChrome; |
3446 | + if (m_session && m_session->lastSurface()) { |
3447 | + m_session->lastSurface()->setShellChrome(shellChrome); |
3448 | + } |
3449 | +} |
3450 | |
3451 | === modified file 'tests/mocks/Unity/Application/ApplicationInfo.h' |
3452 | --- tests/mocks/Unity/Application/ApplicationInfo.h 2016-01-19 21:41:34 +0000 |
3453 | +++ tests/mocks/Unity/Application/ApplicationInfo.h 2016-03-15 20:13:37 +0000 |
3454 | @@ -24,6 +24,7 @@ |
3455 | |
3456 | // unity-api |
3457 | #include <unity/shell/application/ApplicationInfoInterface.h> |
3458 | +#include <unity/shell/application/Mir.h> |
3459 | |
3460 | using namespace unity::shell::application; |
3461 | |
3462 | @@ -59,7 +60,7 @@ |
3463 | |
3464 | QUrl icon() const override { return m_icon; } |
3465 | |
3466 | - void setStage(Stage value); |
3467 | + Q_INVOKABLE void setStage(Stage value); // invokable only for mock |
3468 | Stage stage() const override { return m_stage; } |
3469 | |
3470 | Q_INVOKABLE void setState(State value); |
3471 | @@ -78,7 +79,7 @@ |
3472 | QString screenshot() const { return m_screenshotFileName; } |
3473 | |
3474 | void setFullscreen(bool value); |
3475 | - bool fullscreen() const { return m_fullscreen; } |
3476 | + bool fullscreen() const; |
3477 | |
3478 | Qt::ScreenOrientations supportedOrientations() const override; |
3479 | void setSupportedOrientations(Qt::ScreenOrientations orientations); |
3480 | @@ -97,6 +98,8 @@ |
3481 | |
3482 | QSize initialSurfaceSize() const override; |
3483 | void setInitialSurfaceSize(const QSize &size) override; |
3484 | + |
3485 | + Q_INVOKABLE void setShellChrome(Mir::ShellChrome shellChrome); |
3486 | public: |
3487 | void setSession(Session* session); |
3488 | Session* session() const { return m_session; } |
3489 | @@ -134,6 +137,7 @@ |
3490 | QSize m_initialSurfaceSize; |
3491 | |
3492 | bool m_manualSurfaceCreation; |
3493 | + Mir::ShellChrome m_shellChrome; |
3494 | }; |
3495 | |
3496 | Q_DECLARE_METATYPE(ApplicationInfo*) |
3497 | |
3498 | === modified file 'tests/mocks/Unity/Application/ApplicationManager.cpp' |
3499 | --- tests/mocks/Unity/Application/ApplicationManager.cpp 2016-03-15 20:13:36 +0000 |
3500 | +++ tests/mocks/Unity/Application/ApplicationManager.cpp 2016-03-15 20:13:37 +0000 |
3501 | @@ -328,6 +328,7 @@ |
3502 | application->setName("Camera"); |
3503 | application->setScreenshotId("camera"); |
3504 | application->setIconId("camera"); |
3505 | + application->setShellChrome(Mir::LowChrome); |
3506 | application->setFullscreen(true); |
3507 | application->setSupportedOrientations(Qt::PortraitOrientation |
3508 | | Qt::LandscapeOrientation |
3509 | @@ -341,7 +342,8 @@ |
3510 | application->setName("Gallery"); |
3511 | application->setScreenshotId("gallery"); |
3512 | application->setIconId("gallery"); |
3513 | - application->setFullscreen(true); |
3514 | + application->setShellChrome(Mir::LowChrome); |
3515 | + application->setStage(ApplicationInfo::MainStage); |
3516 | m_availableApplications.append(application); |
3517 | |
3518 | application = new ApplicationInfo(this); |
3519 | @@ -353,7 +355,7 @@ |
3520 | |
3521 | application = new ApplicationInfo(this); |
3522 | application->setAppId("webbrowser-app"); |
3523 | - application->setFullscreen(true); |
3524 | + application->setShellChrome(Mir::LowChrome); |
3525 | application->setName("Browser"); |
3526 | application->setScreenshotId("browser"); |
3527 | application->setIconId("browser"); |
3528 | @@ -378,7 +380,7 @@ |
3529 | application->setName("GMail"); |
3530 | application->setIconId("gmail"); |
3531 | application->setScreenshotId("gmail-webapp.svg"); |
3532 | - application->setFullscreen(false); |
3533 | + application->setStage(ApplicationInfo::MainStage); |
3534 | application->setSupportedOrientations(Qt::PortraitOrientation |
3535 | | Qt::LandscapeOrientation |
3536 | | Qt::InvertedPortraitOrientation |
3537 | @@ -390,7 +392,7 @@ |
3538 | application->setName("Music"); |
3539 | application->setIconId("soundcloud"); |
3540 | application->setScreenshotId("music"); |
3541 | - application->setFullscreen(false); |
3542 | + application->setStage(ApplicationInfo::MainStage); |
3543 | application->setSupportedOrientations(Qt::PortraitOrientation |
3544 | | Qt::LandscapeOrientation |
3545 | | Qt::InvertedPortraitOrientation |
3546 | |
3547 | === modified file 'tests/mocks/Unity/Application/MirSurface.cpp' |
3548 | --- tests/mocks/Unity/Application/MirSurface.cpp 2016-03-10 22:39:10 +0000 |
3549 | +++ tests/mocks/Unity/Application/MirSurface.cpp 2016-03-15 20:13:37 +0000 |
3550 | @@ -38,6 +38,7 @@ |
3551 | , m_width(-1) |
3552 | , m_height(-1) |
3553 | , m_slowToResize(false) |
3554 | + , m_shellChrome(Mir::NormalChrome) |
3555 | { |
3556 | // qDebug() << "MirSurface::MirSurface() " << name; |
3557 | QQmlEngine::setObjectOwnership(this, QQmlEngine::CppOwnership); |
3558 | @@ -134,6 +135,21 @@ |
3559 | } |
3560 | |
3561 | |
3562 | +Mir::ShellChrome MirSurface::shellChrome() const |
3563 | +{ |
3564 | + return m_shellChrome; |
3565 | +} |
3566 | + |
3567 | +void MirSurface::setShellChrome(Mir::ShellChrome shellChrome) |
3568 | +{ |
3569 | + if (shellChrome == m_shellChrome) |
3570 | + return; |
3571 | + |
3572 | + m_shellChrome = shellChrome; |
3573 | + Q_EMIT shellChromeChanged(shellChrome); |
3574 | +} |
3575 | + |
3576 | + |
3577 | |
3578 | void MirSurface::registerView(qintptr viewId) |
3579 | { |
3580 | |
3581 | === modified file 'tests/mocks/Unity/Application/MirSurface.h' |
3582 | --- tests/mocks/Unity/Application/MirSurface.h 2016-03-01 12:56:35 +0000 |
3583 | +++ tests/mocks/Unity/Application/MirSurface.h 2016-03-15 20:13:37 +0000 |
3584 | @@ -74,10 +74,13 @@ |
3585 | int widthIncrement() const override { return m_widthIncrement; } |
3586 | int heightIncrement() const override { return m_heightIncrement; } |
3587 | |
3588 | + Mir::ShellChrome shellChrome() const override; |
3589 | + |
3590 | //// |
3591 | // API for tests |
3592 | |
3593 | Q_INVOKABLE void setLive(bool live); |
3594 | + Q_INVOKABLE void setShellChrome(Mir::ShellChrome shellChrome); |
3595 | |
3596 | void registerView(qintptr viewId); |
3597 | void unregisterView(qintptr viewId); |
3598 | @@ -109,9 +112,6 @@ |
3599 | void setActiveFocus(bool); |
3600 | |
3601 | Q_SIGNALS: |
3602 | - void stateChanged(Mir::State); |
3603 | - void liveChanged(bool live); |
3604 | - void orientationAngleChanged(Mir::OrientationAngle angle); |
3605 | void widthChanged(); |
3606 | void heightChanged(); |
3607 | void slowToResizeChanged(); |
3608 | @@ -152,6 +152,8 @@ |
3609 | QSize m_delayedResize; |
3610 | QSize m_pendingResize; |
3611 | |
3612 | + Mir::ShellChrome m_shellChrome; |
3613 | + |
3614 | struct View { |
3615 | bool visible; |
3616 | }; |
3617 | |
3618 | === modified file 'tests/mocks/Unity/Application/MirSurfaceItem.cpp' |
3619 | --- tests/mocks/Unity/Application/MirSurfaceItem.cpp 2016-03-15 20:13:36 +0000 |
3620 | +++ tests/mocks/Unity/Application/MirSurfaceItem.cpp 2016-03-15 20:13:37 +0000 |
3621 | @@ -100,6 +100,15 @@ |
3622 | } |
3623 | } |
3624 | |
3625 | +Mir::ShellChrome MirSurfaceItem::shellChrome() const |
3626 | +{ |
3627 | + if (m_qmlSurface) { |
3628 | + return m_qmlSurface->shellChrome(); |
3629 | + } else { |
3630 | + return Mir::NormalChrome; |
3631 | + } |
3632 | +} |
3633 | + |
3634 | Mir::OrientationAngle MirSurfaceItem::orientationAngle() const |
3635 | { |
3636 | if (m_qmlSurface) { |
3637 | |
3638 | === modified file 'tests/mocks/Unity/Application/MirSurfaceItem.h' |
3639 | --- tests/mocks/Unity/Application/MirSurfaceItem.h 2016-03-15 20:13:36 +0000 |
3640 | +++ tests/mocks/Unity/Application/MirSurfaceItem.h 2016-03-15 20:13:37 +0000 |
3641 | @@ -47,6 +47,7 @@ |
3642 | Mir::Type type() const override; |
3643 | QString name() const override; |
3644 | bool live() const override; |
3645 | + Mir::ShellChrome shellChrome() const override; |
3646 | |
3647 | Mir::State surfaceState() const override; |
3648 | void setSurfaceState(Mir::State) override {} |
3649 | |
3650 | === modified file 'tests/mocks/Unity/Application/Session.cpp' |
3651 | --- tests/mocks/Unity/Application/Session.cpp 2015-12-01 12:17:24 +0000 |
3652 | +++ tests/mocks/Unity/Application/Session.cpp 2016-03-15 20:13:37 +0000 |
3653 | @@ -34,6 +34,7 @@ |
3654 | , m_surface(nullptr) |
3655 | , m_parentSession(nullptr) |
3656 | , m_children(new SessionModel(this)) |
3657 | + , m_fullscreen(false) |
3658 | { |
3659 | // qDebug() << "Session::Session() " << this->name(); |
3660 | |
3661 | @@ -71,6 +72,25 @@ |
3662 | deleteLater(); |
3663 | } |
3664 | |
3665 | +void Session::updateFullscreenProperty() |
3666 | +{ |
3667 | + if (m_surfaces.rowCount() > 0) { |
3668 | + // TODO: Figure out something better |
3669 | + setFullscreen(lastSurface()->state() == Mir::FullscreenState); |
3670 | + } else { |
3671 | + // Keep the current value of the fullscreen property until we get a new |
3672 | + // surface |
3673 | + } |
3674 | +} |
3675 | + |
3676 | +void Session::setFullscreen(bool fullscreen) |
3677 | +{ |
3678 | + if (m_fullscreen != fullscreen) { |
3679 | + m_fullscreen = fullscreen; |
3680 | + Q_EMIT fullscreenChanged(m_fullscreen); |
3681 | + } |
3682 | +} |
3683 | + |
3684 | void Session::setApplication(ApplicationInfo* application) |
3685 | { |
3686 | if (m_application == application) |
3687 | @@ -82,15 +102,18 @@ |
3688 | |
3689 | void Session::appendSurface(MirSurface* surface) |
3690 | { |
3691 | - // qDebug() << "Session::appendSurface - session=" << name() << "surface=" << surface; |
3692 | + qDebug() << "Session::appendSurface - session=" << name() << "surface=" << surface; |
3693 | |
3694 | m_surfaces.insert(m_surfaces.rowCount(), surface); |
3695 | |
3696 | + connect(surface, &MirSurfaceInterface::stateChanged, this, &Session::updateFullscreenProperty); |
3697 | connect(surface, &QObject::destroyed, |
3698 | this, [this, surface]() { this->removeSurface(surface); }); |
3699 | |
3700 | Q_EMIT lastSurfaceChanged(surface); |
3701 | Q_EMIT surfaceAdded(surface); |
3702 | + |
3703 | + updateFullscreenProperty(); |
3704 | } |
3705 | |
3706 | void Session::removeSurface(MirSurface* surface) |
3707 | @@ -99,6 +122,8 @@ |
3708 | if (m_surfaces.contains(surface)) { |
3709 | m_surfaces.remove(surface); |
3710 | } |
3711 | + |
3712 | + updateFullscreenProperty(); |
3713 | } |
3714 | |
3715 | void Session::setScreenshot(const QUrl& screenshot) |
3716 | |
3717 | === modified file 'tests/mocks/Unity/Application/Session.h' |
3718 | --- tests/mocks/Unity/Application/Session.h 2015-12-01 12:17:24 +0000 |
3719 | +++ tests/mocks/Unity/Application/Session.h 2016-03-15 20:13:37 +0000 |
3720 | @@ -47,6 +47,7 @@ |
3721 | //getters |
3722 | QString name() const { return m_name; } |
3723 | bool live() const { return m_live; } |
3724 | + bool fullscreen() const { return m_fullscreen; } |
3725 | ApplicationInfo* application() const { return m_application; } |
3726 | MirSurface *lastSurface() const; |
3727 | ObjectListModel<MirSurface>* surfaces() const; |
3728 | @@ -57,6 +58,7 @@ |
3729 | void removeSurface(MirSurface* surface); |
3730 | void setScreenshot(const QUrl& m_screenshot); |
3731 | void setLive(bool live); |
3732 | + void setFullscreen(bool fullscreen); |
3733 | |
3734 | Q_INVOKABLE void addChildSession(Session* session); |
3735 | void insertChildSession(uint index, Session* session); |
3736 | @@ -68,6 +70,7 @@ |
3737 | void liveChanged(bool live); |
3738 | void surfaceAdded(MirSurface *surface); |
3739 | void lastSurfaceChanged(MirSurface *surface); |
3740 | + void fullscreenChanged(bool fullscreen); |
3741 | |
3742 | // internal mock use |
3743 | void deregister(); |
3744 | @@ -75,6 +78,9 @@ |
3745 | public Q_SLOTS: |
3746 | Q_INVOKABLE void createSurface(); |
3747 | |
3748 | +private Q_SLOTS: |
3749 | + void updateFullscreenProperty(); |
3750 | + |
3751 | private: |
3752 | SessionModel* childSessions() const; |
3753 | void setParentSession(Session* session); |
3754 | @@ -87,6 +93,7 @@ |
3755 | Session* m_parentSession; |
3756 | SessionModel* m_children; |
3757 | ObjectListModel<MirSurface> m_surfaces; |
3758 | + bool m_fullscreen; |
3759 | |
3760 | friend class ApplicationTestInterface; |
3761 | }; |
3762 | |
3763 | === modified file 'tests/mocks/Utils/CMakeLists.txt' |
3764 | --- tests/mocks/Utils/CMakeLists.txt 2016-03-15 20:13:36 +0000 |
3765 | +++ tests/mocks/Utils/CMakeLists.txt 2016-03-15 20:13:37 +0000 |
3766 | @@ -12,7 +12,7 @@ |
3767 | ${CMAKE_SOURCE_DIR}/plugins/Utils/qlimitproxymodelqml.cpp |
3768 | ${CMAKE_SOURCE_DIR}/plugins/Utils/unitysortfilterproxymodelqml.cpp |
3769 | ${CMAKE_SOURCE_DIR}/plugins/Utils/unitymenumodelpaths.cpp |
3770 | - ${CMAKE_SOURCE_DIR}/plugins/Utils/windowkeysfilter.cpp |
3771 | + ${CMAKE_SOURCE_DIR}/plugins/Utils/windowinputfilter.cpp |
3772 | ${CMAKE_SOURCE_DIR}/plugins/Utils/windowscreenshotprovider.cpp |
3773 | ${CMAKE_SOURCE_DIR}/plugins/Utils/easingcurve.cpp |
3774 | ${CMAKE_SOURCE_DIR}/plugins/Utils/inputwatcher.cpp |
3775 | |
3776 | === modified file 'tests/mocks/Utils/Utils.qmltypes' |
3777 | --- tests/mocks/Utils/Utils.qmltypes 2015-07-15 11:37:23 +0000 |
3778 | +++ tests/mocks/Utils/Utils.qmltypes 2016-03-15 20:13:37 +0000 |
3779 | @@ -145,10 +145,10 @@ |
3780 | } |
3781 | } |
3782 | Component { |
3783 | - name: "WindowKeysFilter" |
3784 | + name: "WindowInputFilter" |
3785 | defaultProperty: "data" |
3786 | prototype: "QQuickItem" |
3787 | - exports: ["Utils/WindowKeysFilter 0.1"] |
3788 | + exports: ["Utils/WindowInputFilter 0.1"] |
3789 | exportMetaObjectRevisions: [0] |
3790 | } |
3791 | Component { |
3792 | |
3793 | === modified file 'tests/mocks/Utils/plugin.cpp' |
3794 | --- tests/mocks/Utils/plugin.cpp 2016-03-15 20:13:36 +0000 |
3795 | +++ tests/mocks/Utils/plugin.cpp 2016-03-15 20:13:37 +0000 |
3796 | @@ -32,7 +32,7 @@ |
3797 | #include <qlimitproxymodelqml.h> |
3798 | #include <unitysortfilterproxymodelqml.h> |
3799 | #include <unitymenumodelpaths.h> |
3800 | -#include <windowkeysfilter.h> |
3801 | +#include <windowinputfilter.h> |
3802 | #include <windowscreenshotprovider.h> |
3803 | #include <easingcurve.h> |
3804 | #include <timezoneFormatter.h> |
3805 | @@ -69,7 +69,7 @@ |
3806 | qmlRegisterType<QLimitProxyModelQML>(uri, 0, 1, "LimitProxyModel"); |
3807 | qmlRegisterType<UnitySortFilterProxyModelQML>(uri, 0, 1, "UnitySortFilterProxyModel"); |
3808 | qmlRegisterType<UnityMenuModelPaths>(uri, 0, 1, "UnityMenuModelPaths"); |
3809 | - qmlRegisterType<WindowKeysFilter>(uri, 0, 1, "WindowKeysFilter"); |
3810 | + qmlRegisterType<WindowInputFilter>(uri, 0, 1, "WindowInputFilter"); |
3811 | qmlRegisterType<EasingCurve>(uri, 0, 1, "EasingCurve"); |
3812 | qmlRegisterSingletonType<WindowStateStorage>(uri, 0, 1, "WindowStateStorage", createWindowStateStorage); |
3813 | qmlRegisterType<InputWatcher>(uri, 0, 1, "InputWatcher"); |
3814 | |
3815 | === modified file 'tests/plugins/AccountsService/PropertiesServer.cpp' |
3816 | --- tests/plugins/AccountsService/PropertiesServer.cpp 2016-03-10 22:42:54 +0000 |
3817 | +++ tests/plugins/AccountsService/PropertiesServer.cpp 2016-03-15 20:13:37 +0000 |
3818 | @@ -89,6 +89,7 @@ |
3819 | void PropertiesServer::Reset() |
3820 | { |
3821 | m_properties["com.canonical.unity.AccountsService"]["demo-edges"] = false; |
3822 | + m_properties["com.canonical.unity.AccountsService"]["DemoEdgesCompleted"] = QStringList(); |
3823 | m_properties["com.canonical.unity.AccountsService"]["LauncherItems"] = QVariant::fromValue(QList<QVariantMap>()); |
3824 | m_properties["com.canonical.unity.AccountsService.Private"]["FailedLogins"] = 0; |
3825 | m_properties["com.ubuntu.touch.AccountsService.SecurityPrivacy"]["StatsWelcomeScreen"] = true; |
3826 | |
3827 | === modified file 'tests/plugins/AccountsService/client.cpp' |
3828 | --- tests/plugins/AccountsService/client.cpp 2016-02-25 10:57:17 +0000 |
3829 | +++ tests/plugins/AccountsService/client.cpp 2016-03-15 20:13:37 +0000 |
3830 | @@ -117,6 +117,43 @@ |
3831 | QCOMPARE(session.hereEnabled(), true); |
3832 | } |
3833 | |
3834 | + void testMarkDemoEdgeCompleted() |
3835 | + { |
3836 | + AccountsService session(this, QTest::currentTestFunction()); |
3837 | + QSignalSpy changedSpy(&session, &AccountsService::demoEdgesCompletedChanged); |
3838 | + |
3839 | + QCOMPARE(changedSpy.count(), 0); |
3840 | + QCOMPARE(session.demoEdgesCompleted(), QStringList()); |
3841 | + |
3842 | + session.markDemoEdgeCompleted("testedge"); |
3843 | + QCOMPARE(changedSpy.count(), 1); |
3844 | + QCOMPARE(session.demoEdgesCompleted(), QStringList() << "testedge"); |
3845 | + |
3846 | + session.markDemoEdgeCompleted("testedge"); |
3847 | + QCOMPARE(changedSpy.count(), 1); |
3848 | + QCOMPARE(session.demoEdgesCompleted(), QStringList() << "testedge"); |
3849 | + |
3850 | + session.markDemoEdgeCompleted("testedge2"); |
3851 | + QCOMPARE(changedSpy.count(), 2); |
3852 | + QCOMPARE(session.demoEdgesCompleted(), QStringList() << "testedge" << "testedge2"); |
3853 | + } |
3854 | + |
3855 | + void testAsynchronousChangeForDemoEdgesCompleted() |
3856 | + { |
3857 | + AccountsService session(this, QTest::currentTestFunction()); |
3858 | + QSignalSpy changedSpy(&session, &AccountsService::demoEdgesCompletedChanged); |
3859 | + |
3860 | + QCOMPARE(changedSpy.count(), 0); |
3861 | + QCOMPARE(session.demoEdgesCompleted(), QStringList()); |
3862 | + |
3863 | + ASSERT_DBUS_CALL(m_userInterface->call("Set", |
3864 | + "com.canonical.unity.AccountsService", |
3865 | + "DemoEdgesCompleted", |
3866 | + dbusVariant(QStringList() << "testedge"))); |
3867 | + QTRY_COMPARE(changedSpy.count(), 1); |
3868 | + QCOMPARE(session.demoEdgesCompleted(), QStringList() << "testedge"); |
3869 | + } |
3870 | + |
3871 | void testAsynchronousChangeForDemoEdges() |
3872 | { |
3873 | AccountsService session(this, QTest::currentTestFunction()); |
3874 | |
3875 | === modified file 'tests/qmltests/Components/tst_PhysicalKeysMapper.qml' |
3876 | --- tests/qmltests/Components/tst_PhysicalKeysMapper.qml 2016-01-15 10:21:18 +0000 |
3877 | +++ tests/qmltests/Components/tst_PhysicalKeysMapper.qml 2016-03-15 20:13:37 +0000 |
3878 | @@ -26,9 +26,9 @@ |
3879 | |
3880 | property var physicalKeysMapper: loader.item |
3881 | |
3882 | - WindowKeysFilter { |
3883 | - Keys.onPressed: physicalKeysMapper.onKeyPressed(event, currentEventTimestamp); |
3884 | - Keys.onReleased: physicalKeysMapper.onKeyReleased(event, currentEventTimestamp); |
3885 | + WindowInputFilter { |
3886 | + Keys.onPressed: physicalKeysMapper.onKeyPressed(event, lastInputTimestamp); |
3887 | + Keys.onReleased: physicalKeysMapper.onKeyReleased(event, lastInputTimestamp); |
3888 | } |
3889 | |
3890 | Loader { |
3891 | |
3892 | === modified file 'tests/qmltests/Greeter/tst_Greeter.qml' |
3893 | --- tests/qmltests/Greeter/tst_Greeter.qml 2016-01-11 17:37:02 +0000 |
3894 | +++ tests/qmltests/Greeter/tst_Greeter.qml 2016-03-15 20:13:37 +0000 |
3895 | @@ -328,9 +328,15 @@ |
3896 | LightDM.Greeter.active = true; |
3897 | |
3898 | greeter.forcedUnlock = true; |
3899 | - compare(view.locked, false); |
3900 | + compare(greeter.required, false); |
3901 | greeter.forcedUnlock = false; |
3902 | |
3903 | + // Now recover from tearing down the view above |
3904 | + LightDM.Greeter.showGreeter(); |
3905 | + tryCompare(greeter, "required", true); |
3906 | + tryCompare(greeter, "waiting", false); |
3907 | + view = findChild(greeter, "testView"); |
3908 | + |
3909 | selectUser("no-password"); |
3910 | tryCompare(view, "locked", false); |
3911 | selectUser("has-password"); |
3912 | |
3913 | === modified file 'tests/qmltests/Tutorial/tst_Tutorial.qml' |
3914 | --- tests/qmltests/Tutorial/tst_Tutorial.qml 2015-09-02 07:42:27 +0000 |
3915 | +++ tests/qmltests/Tutorial/tst_Tutorial.qml 2016-03-15 20:13:37 +0000 |
3916 | @@ -19,15 +19,19 @@ |
3917 | import AccountsService 0.1 |
3918 | import IntegratedLightDM 0.1 as LightDM |
3919 | import Ubuntu.Components 1.3 |
3920 | +import Ubuntu.Components.ListItems 1.3 |
3921 | +import Ubuntu.Telephony 0.1 as Telephony |
3922 | import Unity.Application 0.1 |
3923 | import Unity.Test 0.1 as UT |
3924 | |
3925 | import "../../../qml" |
3926 | +import "../../../qml/Components" |
3927 | |
3928 | -Item { |
3929 | +Rectangle { |
3930 | id: root |
3931 | - width: shellLoader.width + buttons.width |
3932 | - height: shellLoader.height |
3933 | + color: UbuntuColors.lightGrey |
3934 | + width: units.gu(100) + buttons.width |
3935 | + height: units.gu(71) |
3936 | |
3937 | QtObject { |
3938 | id: applicationArguments |
3939 | @@ -45,6 +49,11 @@ |
3940 | } |
3941 | } |
3942 | |
3943 | + Telephony.CallEntry { |
3944 | + id: phoneCall |
3945 | + phoneNumber: "+447812221111" |
3946 | + } |
3947 | + |
3948 | Component.onCompleted: { |
3949 | // must set the mock mode before loading the Shell |
3950 | LightDM.Greeter.mockMode = "single-pin"; |
3951 | @@ -52,21 +61,63 @@ |
3952 | shellLoader.active = true; |
3953 | } |
3954 | |
3955 | - Row { |
3956 | - spacing: 0 |
3957 | - anchors.fill: parent |
3958 | + Item { |
3959 | + id: shellContainer |
3960 | + anchors.left: root.left |
3961 | + anchors.right: buttons.left |
3962 | + anchors.top: root.top |
3963 | + anchors.bottom: root.bottom |
3964 | |
3965 | Loader { |
3966 | id: shellLoader |
3967 | |
3968 | active: false |
3969 | - width: units.gu(40) |
3970 | - height: units.gu(71) |
3971 | + anchors.horizontalCenter: parent.horizontalCenter |
3972 | + anchors.top: parent.top |
3973 | + anchors.bottom: parent.bottom |
3974 | + |
3975 | + property int shellOrientation: Qt.PortraitOrientation |
3976 | + property int nativeOrientation: Qt.PortraitOrientation |
3977 | + property int primaryOrientation: Qt.PortraitOrientation |
3978 | + |
3979 | + state: modeSelector.model[modeSelector.selectedIndex] |
3980 | + states: [ |
3981 | + State { |
3982 | + name: "phone" |
3983 | + PropertyChanges { |
3984 | + target: shellLoader |
3985 | + width: units.gu(40) |
3986 | + } |
3987 | + }, |
3988 | + State { |
3989 | + name: "tablet" |
3990 | + PropertyChanges { |
3991 | + target: shellLoader |
3992 | + width: units.gu(100) |
3993 | + shellOrientation: Qt.LandscapeOrientation |
3994 | + nativeOrientation: Qt.LandscapeOrientation |
3995 | + primaryOrientation: Qt.LandscapeOrientation |
3996 | + } |
3997 | + }, |
3998 | + State { |
3999 | + name: "desktop" |
4000 | + PropertyChanges { |
4001 | + target: shellLoader |
4002 | + width: units.gu(100) |
4003 | + } |
4004 | + } |
4005 | + ] |
4006 | |
4007 | property bool itemDestroyed: false |
4008 | sourceComponent: Component { |
4009 | Shell { |
4010 | + usageScenario: shellLoader.state |
4011 | property string indicatorProfile: "phone" |
4012 | + orientation: shellLoader.shellOrientation |
4013 | + orientations: Orientations { |
4014 | + native_: shellLoader.nativeOrientation |
4015 | + primary: shellLoader.primaryOrientation |
4016 | + } |
4017 | |
4018 | Component.onDestruction: { |
4019 | shellLoader.itemDestroyed = true; |
4020 | @@ -74,29 +125,92 @@ |
4021 | } |
4022 | } |
4023 | } |
4024 | - |
4025 | - Rectangle { |
4026 | - id: buttons |
4027 | - color: "white" |
4028 | - width: units.gu(30) |
4029 | - height: shellLoader.height |
4030 | - |
4031 | - Column { |
4032 | - anchors { left: parent.left; right: parent.right; top: parent.top; margins: units.gu(1) } |
4033 | - spacing: units.gu(1) |
4034 | - Row { |
4035 | - anchors { left: parent.left; right: parent.right } |
4036 | - Button { |
4037 | - text: "Restart Tutorial" |
4038 | - onClicked: { |
4039 | - if (shellLoader.status !== Loader.Ready) |
4040 | - return; |
4041 | - |
4042 | - AccountsService.demoEdges = false; |
4043 | - AccountsService.demoEdges = true; |
4044 | - } |
4045 | - } |
4046 | - } |
4047 | + } |
4048 | + |
4049 | + Rectangle { |
4050 | + id: buttons |
4051 | + color: UbuntuColors.darkGrey |
4052 | + width: units.gu(30) |
4053 | + anchors.top: root.top |
4054 | + anchors.bottom: root.bottom |
4055 | + anchors.right: root.right |
4056 | + |
4057 | + Column { |
4058 | + anchors { left: parent.left; right: parent.right; top: parent.top; margins: units.gu(1) } |
4059 | + spacing: units.gu(1) |
4060 | + Row { |
4061 | + anchors { left: parent.left; right: parent.right } |
4062 | + Button { |
4063 | + text: "Hide Greeter" |
4064 | + onClicked: { |
4065 | + if (shellLoader.status !== Loader.Ready) |
4066 | + return; |
4067 | + |
4068 | + var greeter = testCase.findChild(shellLoader.item, "greeter"); |
4069 | + if (greeter.shown) { |
4070 | + greeter.hide(); |
4071 | + } |
4072 | + } |
4073 | + } |
4074 | + } |
4075 | + |
4076 | + Row { |
4077 | + anchors { left: parent.left; right: parent.right } |
4078 | + Button { |
4079 | + text: "Restart Tutorial" |
4080 | + onClicked: { |
4081 | + if (shellLoader.status !== Loader.Ready) |
4082 | + return; |
4083 | + |
4084 | + AccountsService.demoEdges = false; |
4085 | + AccountsService.demoEdgesCompleted = []; |
4086 | + AccountsService.demoEdges = true; |
4087 | + } |
4088 | + } |
4089 | + } |
4090 | + |
4091 | + Row { |
4092 | + anchors { left: parent.left; right: parent.right } |
4093 | + CheckBox { |
4094 | + onCheckedChanged: { |
4095 | + if (checked) { |
4096 | + callManager.foregroundCall = phoneCall; |
4097 | + } else { |
4098 | + callManager.foregroundCall = null; |
4099 | + } |
4100 | + } |
4101 | + } |
4102 | + Label { |
4103 | + text: "Active Call" |
4104 | + anchors.verticalCenter: parent.verticalCenter |
4105 | + } |
4106 | + } |
4107 | + |
4108 | + Row { |
4109 | + anchors { left: parent.left; right: parent.right } |
4110 | + CheckBox { |
4111 | + activeFocusOnPress: false |
4112 | + onCheckedChanged: { |
4113 | + var surface = SurfaceManager.inputMethodSurface; |
4114 | + if (checked) { |
4115 | + surface.setState(Mir.RestoredState); |
4116 | + } else { |
4117 | + surface.setState(Mir.MinimizedState); |
4118 | + } |
4119 | + } |
4120 | + } |
4121 | + Label { |
4122 | + text: "Input Method" |
4123 | + anchors.verticalCenter: parent.verticalCenter |
4124 | + } |
4125 | + } |
4126 | + |
4127 | + ItemSelector { |
4128 | + id: modeSelector |
4129 | + anchors { left: parent.left; right: parent.right } |
4130 | + activeFocusOnPress: false |
4131 | + text: "Mode" |
4132 | + model: ["phone", "tablet", "desktop"] |
4133 | } |
4134 | } |
4135 | } |
4136 | @@ -111,17 +225,21 @@ |
4137 | property real halfHeight: shell ? shell.height / 2 : 0 |
4138 | |
4139 | function init() { |
4140 | - tryCompare(shell, "enabled", true); // enabled by greeter when ready |
4141 | + prepareShell(); |
4142 | |
4143 | - AccountsService.demoEdges = false; |
4144 | - AccountsService.demoEdges = true; |
4145 | - swipeAwayGreeter(); |
4146 | + var tutorialLeft = findChild(shell, "tutorialLeft"); |
4147 | + tryCompare(tutorialLeft, "opacity", 1); |
4148 | } |
4149 | |
4150 | function cleanup() { |
4151 | + resetLoader("phone"); |
4152 | + } |
4153 | + |
4154 | + function resetLoader(state) { |
4155 | shellLoader.itemDestroyed = false; |
4156 | |
4157 | shellLoader.active = false; |
4158 | + shellLoader.state = state; |
4159 | |
4160 | tryCompare(shellLoader, "status", Loader.Null); |
4161 | tryCompare(shellLoader, "item", null); |
4162 | @@ -133,6 +251,11 @@ |
4163 | // Shell instance gets destroyed. |
4164 | tryCompare(shellLoader, "itemDestroyed", true); |
4165 | |
4166 | + // Reset any futzing our tests may have done with persistent objects |
4167 | + var app = ApplicationManager.findApplication("dialer-app"); |
4168 | + if (app) { |
4169 | + app.setStage(ApplicationInfoInterface.SideStage); |
4170 | + } |
4171 | // kill all (fake) running apps |
4172 | killApps(); |
4173 | |
4174 | @@ -143,6 +266,22 @@ |
4175 | removeTimeConstraintsFromDirectionalDragAreas(shellLoader.item); |
4176 | } |
4177 | |
4178 | + function prepareShell() { |
4179 | + tryCompare(shell, "enabled", true); // enabled by greeter when ready |
4180 | + |
4181 | + callManager.foregroundCall = null; |
4182 | + AccountsService.demoEdges = false; |
4183 | + AccountsService.demoEdgesCompleted = []; |
4184 | + AccountsService.demoEdges = true; |
4185 | + |
4186 | + LightDM.Greeter.hideGreeter(); |
4187 | + } |
4188 | + |
4189 | + function loadShell(state) { |
4190 | + resetLoader(state); |
4191 | + prepareShell(); |
4192 | + } |
4193 | + |
4194 | function killApps() { |
4195 | while (ApplicationManager.count > 1) { |
4196 | var appIndex = ApplicationManager.get(0).appId == "unity8-dash" ? 1 : 0 |
4197 | @@ -163,234 +302,486 @@ |
4198 | waitForRendering(greeter); |
4199 | } |
4200 | |
4201 | - function waitForPage(name) { |
4202 | - waitForRendering(findChild(shell, name)); |
4203 | - var page = findChild(shell, name); |
4204 | - tryCompare(page, "shown", true); |
4205 | - tryCompare(page.showAnimation, "running", false); |
4206 | - return page; |
4207 | - } |
4208 | - |
4209 | - function checkTopEdge() { |
4210 | - touchFlick(shell, halfWidth, 0, halfWidth, halfHeight); |
4211 | - |
4212 | + function openTutorialTop() { |
4213 | + var tutorialLeftLoader = findChild(shell, "tutorialLeftLoader"); |
4214 | + var tutorialTop = findChild(shell, "tutorialTop"); |
4215 | + var tutorialTopTimer = findInvisibleChild(tutorialTop, "tutorialTopTimer"); |
4216 | + |
4217 | + tutorialTopTimer.interval = 1; |
4218 | + AccountsService.demoEdgesCompleted = ["left", "left-long"]; |
4219 | + |
4220 | + tryCompare(tutorialLeftLoader, "active", false); |
4221 | + tryCompare(tutorialTop, "shown", true); |
4222 | + tryCompare(tutorialTop, "opacity", 1); |
4223 | + } |
4224 | + |
4225 | + function openTutorialRight() { |
4226 | + var tutorialLeftLoader = findChild(shell, "tutorialLeftLoader"); |
4227 | + var tutorialRight = findChild(shell, "tutorialRight"); |
4228 | + |
4229 | + AccountsService.demoEdgesCompleted = ["left", "left-long", "top"]; |
4230 | + ApplicationManager.startApplication("gallery-app"); |
4231 | + ApplicationManager.startApplication("facebook-webapp"); |
4232 | + |
4233 | + tryCompare(tutorialLeftLoader, "active", false); |
4234 | + tryCompare(tutorialRight, "shown", true); |
4235 | + tryCompare(tutorialRight, "opacity", 1); |
4236 | + } |
4237 | + |
4238 | + function openTutorialBottom() { |
4239 | + var tutorialLeftLoader = findChild(shell, "tutorialLeftLoader"); |
4240 | + var tutorialBottom = findChild(shell, "tutorialBottom"); |
4241 | + |
4242 | + AccountsService.demoEdgesCompleted = ["left", "left-long", "top", "right"]; |
4243 | + ApplicationManager.startApplication("dialer-app"); |
4244 | + |
4245 | + tryCompare(tutorialLeftLoader, "active", false); |
4246 | + tryCompare(tutorialBottom, "shown", true); |
4247 | + tryCompare(tutorialBottom, "opacity", 1); |
4248 | + } |
4249 | + |
4250 | + function test_tutorialLeftEdges() { |
4251 | + var tutorial = findChild(shell, "tutorial"); |
4252 | + var tutorialLeft = findChild(tutorial, "tutorialLeft"); |
4253 | + var launcher = findChild(shell, "launcher"); |
4254 | + var stage = findChild(shell, "stage"); |
4255 | var panel = findChild(shell, "panel"); |
4256 | - tryCompare(panel.indicators, "fullyClosed", true); |
4257 | - } |
4258 | - |
4259 | - function checkLeftEdge() { |
4260 | - touchFlick(shell, 0, halfHeight, halfWidth, halfHeight); |
4261 | - |
4262 | - var launcher = findChild(shell, "launcher"); |
4263 | - tryCompare(launcher, "state", ""); |
4264 | - } |
4265 | - |
4266 | - function checkRightEdge() { |
4267 | - if (shell.usageScenario === "phone") { |
4268 | - touchFlick(shell, shell.width, halfHeight, halfWidth, halfHeight); |
4269 | - |
4270 | - var stage = findChild(shell, "stage"); |
4271 | - var spreadView = findChild(stage, "spreadView"); |
4272 | - tryCompare(spreadView, "phase", 0); |
4273 | - } |
4274 | - } |
4275 | - |
4276 | - function checkBottomEdge() { |
4277 | - // Can't actually check effect of swipe, since dash isn't really loaded |
4278 | - var applicationsDisplayLoader = findChild(shell, "applicationsDisplayLoader"); |
4279 | - tryCompare(applicationsDisplayLoader, "interactive", false); |
4280 | - } |
4281 | - |
4282 | - function checkFinished() { |
4283 | - tryCompare(AccountsService, "demoEdges", false); |
4284 | - |
4285 | - var tutorial = findChild(shell, "tutorial"); |
4286 | - tryCompare(tutorial, "running", false); |
4287 | - |
4288 | - var launcher = findChild(shell, "launcher"); |
4289 | - tryCompare(launcher, "shown", false); |
4290 | - } |
4291 | - |
4292 | - function goToPage(name) { |
4293 | - var page = waitForPage("tutorialLeft"); |
4294 | - checkTopEdge(); |
4295 | - checkRightEdge(); |
4296 | - checkBottomEdge(); |
4297 | - if (name === "tutorialLeft") return page; |
4298 | - touchFlick(shell, 0, halfHeight, halfWidth, halfHeight); |
4299 | - |
4300 | - page = waitForPage("tutorialLeftFinish"); |
4301 | - if (name === "tutorialLeftFinish") return page; |
4302 | - var tick = findChild(page, "tick"); |
4303 | - tap(tick); |
4304 | - |
4305 | - page = waitForPage("tutorialRight"); |
4306 | - checkTopEdge(); |
4307 | - checkLeftEdge(); |
4308 | - checkBottomEdge(); |
4309 | - if (name === "tutorialRight") return page; |
4310 | - touchFlick(shell, |
4311 | - shell.width, halfHeight, |
4312 | - halfWidth, halfHeight, |
4313 | - true /* beginTouch */, true /* endTouch */, |
4314 | - 20 /* speed */, 50 /* iterations */); |
4315 | - var overlay = findChild(page, "overlay"); |
4316 | - tryCompare(overlay, "shown", true); |
4317 | - var tick = findChild(page, "tick"); |
4318 | - tap(tick); |
4319 | - |
4320 | - var page = waitForPage("tutorialBottom"); |
4321 | - checkTopEdge(); |
4322 | - checkLeftEdge(); |
4323 | - checkRightEdge(); |
4324 | - if (name === "tutorialBottom") return page; |
4325 | - touchFlick(shell, halfWidth, shell.height, halfWidth, halfHeight); |
4326 | - |
4327 | - var page = waitForPage("tutorialBottomFinish"); |
4328 | - checkTopEdge(); |
4329 | - checkLeftEdge(); |
4330 | - checkRightEdge(); |
4331 | - checkBottomEdge(); |
4332 | - if (name === "tutorialBottomFinish") return page; |
4333 | - var tick = findChild(page, "tick"); |
4334 | - tap(tick); |
4335 | - |
4336 | - checkFinished(); |
4337 | - return null; |
4338 | - } |
4339 | - |
4340 | - function test_walkthrough() { |
4341 | - goToPage(null); |
4342 | - } |
4343 | - |
4344 | - function test_skipOnDesktop() { |
4345 | - var tutorial = findChild(shell, "tutorial"); |
4346 | - tryCompare(tutorial, "active", true); |
4347 | - tryCompare(tutorial, "running", true); |
4348 | - |
4349 | - shell.usageScenario = "desktop"; |
4350 | - tryCompare(tutorial, "active", false); |
4351 | - tryCompare(tutorial, "running", false); |
4352 | - } |
4353 | - |
4354 | - function test_launcherShortDrag() { |
4355 | - // goToPage does a normal launcher pull. But here we want to test |
4356 | - // just barely pulling the launcher out and letting go (i.e. not |
4357 | - // triggering the "progress" property of Launcher). |
4358 | - |
4359 | - var left = goToPage("tutorialLeft"); |
4360 | + |
4361 | + verify(tutorial.running); |
4362 | + verify(tutorial.launcherEnabled); |
4363 | + verify(!tutorial.spreadEnabled); |
4364 | + verify(!tutorial.panelEnabled); |
4365 | + verify(tutorialLeft.shown); |
4366 | + verify(launcher.available); |
4367 | + verify(!stage.spreadEnabled); |
4368 | + verify(!panel.indicators.available); |
4369 | + } |
4370 | + |
4371 | + function test_tutorialLeftFinish() { |
4372 | + var tutorial = findChild(shell, "tutorial"); |
4373 | + var tutorialLeft = findChild(tutorial, "tutorialLeft"); |
4374 | + var launcher = findChild(shell, "launcher"); |
4375 | + |
4376 | + touchFlick(shell, 0, halfHeight, halfWidth, halfHeight); |
4377 | + |
4378 | + tryCompare(tutorialLeft, "shown", false); |
4379 | + tryCompare(AccountsService, "demoEdgesCompleted", ["left"]); |
4380 | + tryCompare(launcher, "state", "visible"); |
4381 | + } |
4382 | + |
4383 | + function test_tutorialLeftShortDrag() { |
4384 | + // Here we want to test just barely pulling the launcher out and |
4385 | + // letting go (i.e. not triggering the "progress" property of |
4386 | + // Launcher). |
4387 | + var tutorialLeft = findChild(shell, "tutorialLeft"); |
4388 | + var launcher = findChild(shell, "launcher"); |
4389 | + |
4390 | + // Confirm fade during drag |
4391 | + touchFlick(shell, 0, halfHeight, launcher.panelWidth * 0.4, halfHeight, true, false); |
4392 | + // compare opacity with a bound rather than hard 0.6 because progress doesn't |
4393 | + // always match the drag perfectly (takes a moment for drag to kick in) |
4394 | + tryCompareFunction(function() { |
4395 | + return tutorialLeft.opacity >= 0.6 && tutorialLeft.opacity < 0.7; |
4396 | + }, true); |
4397 | + touchFlick(shell, 0, halfHeight, launcher.panelWidth * 0.4, halfHeight, false, true); |
4398 | + |
4399 | |
4400 | // Make sure we don't do anything if we don't pull the launcher |
4401 | // out much. |
4402 | - var launcher = findChild(shell, "launcher"); |
4403 | touchFlick(shell, 0, halfHeight, launcher.panelWidth * 0.4, halfHeight); |
4404 | tryCompare(launcher, "state", ""); // should remain hidden |
4405 | - tryCompare(left, "shown", true); // and we should still be on left |
4406 | + tryCompare(tutorialLeft, "shown", true); // and we should still be on left |
4407 | + |
4408 | |
4409 | // Now drag out but not past launcher itself |
4410 | touchFlick(shell, 0, halfHeight, launcher.panelWidth * 0.9, halfHeight); |
4411 | |
4412 | - waitForPage("tutorialLeftFinish"); |
4413 | + tryCompare(tutorialLeft, "shown", false); |
4414 | + tryCompare(AccountsService, "demoEdgesCompleted", ["left"]); |
4415 | + tryCompare(launcher, "state", "visible"); |
4416 | } |
4417 | |
4418 | - function test_launcherLongDrag() { |
4419 | - // goToPage does a normal launcher pull. But here we want to test |
4420 | - // a full pull across the page. |
4421 | + function test_tutorialLeftLongDrag() { |
4422 | + // Just confirm that a long drag ("dash" drag) doesn't confuse us |
4423 | |
4424 | - var left = goToPage("tutorialLeft"); |
4425 | + // So that we actually switch to dash and launcher hides |
4426 | + ApplicationManager.startApplication("gallery-app"); |
4427 | |
4428 | var launcher = findChild(shell, "launcher"); |
4429 | + var tutorialLeft = findChild(shell, "tutorialLeft"); |
4430 | touchFlick(shell, 0, halfHeight, shell.width, halfHeight); |
4431 | |
4432 | - var errorTextLabel = findChild(left, "errorTextLabel"); |
4433 | - var errorTitleLabel = findChild(left, "errorTitleLabel"); |
4434 | - tryCompare(launcher, "state", ""); // launcher goes away |
4435 | - tryCompare(left, "shown", true); // still on left page |
4436 | - tryCompare(errorTextLabel, "opacity", 1); // show error |
4437 | - tryCompare(errorTitleLabel, "opacity", 1); // show error |
4438 | - } |
4439 | - |
4440 | - function test_launcherDragBack() { |
4441 | - // goToPage does a full launcher pull. But here we test pulling |
4442 | - // all the way out, then dragging back into place. |
4443 | - |
4444 | - var left = goToPage("tutorialLeft"); |
4445 | - touchFlick(shell, 0, halfHeight, halfWidth, halfHeight, true, false); |
4446 | - touchFlick(shell, halfWidth, halfHeight, 0, halfHeight, false, true); |
4447 | - |
4448 | - tryCompare(left, "shown", true); // and we should still be on left |
4449 | - } |
4450 | - |
4451 | - function test_launcherNoDragGap() { |
4452 | - // See bug 1454882, where if you dragged the launcher while it was |
4453 | - // visible, you could pull it further than the edge of the screen. |
4454 | - |
4455 | - var left = goToPage("tutorialLeft"); |
4456 | - var launcher = findChild(shell, "launcher"); |
4457 | - var teaseAnimation = findInvisibleChild(left, "teaseAnimation"); |
4458 | - |
4459 | - // Wait for launcher to be really out there |
4460 | - tryCompareFunction(function() {return launcher.x > teaseAnimation.maxBounce/2}, true); |
4461 | - verify(teaseAnimation.running); |
4462 | - |
4463 | - // Start a drag, make sure animation stops |
4464 | - touchFlick(shell, 0, halfHeight, units.gu(4), halfHeight, true, false); |
4465 | - verify(!teaseAnimation.running); |
4466 | - verify(launcher.visibleWidth > 0); |
4467 | - verify(launcher.x > 0); |
4468 | - compare(launcher.x, teaseAnimation.bounce); |
4469 | - |
4470 | - // Continue drag, make sure we don't create a gap on the left hand side |
4471 | - touchFlick(shell, units.gu(4), halfHeight, shell.width, halfHeight, false, false); |
4472 | - verify(!teaseAnimation.running); |
4473 | - compare(launcher.visibleWidth, launcher.panelWidth); |
4474 | - compare(launcher.x, 0); |
4475 | - |
4476 | - // Finish and make sure we continue animation |
4477 | - touchFlick(shell, shell.width, halfHeight, shell.width, halfHeight, false, true); |
4478 | - tryCompare(teaseAnimation, "running", true); |
4479 | - } |
4480 | - |
4481 | - function test_spread() { |
4482 | - // Unfortunately, most of what we want to test of the spread is |
4483 | - // "did it render correctly?" but that's hard to test. So instead, |
4484 | - // just poke and prod it a little bit to see if some of the values |
4485 | - // we'd expect to be correct, are so. |
4486 | - |
4487 | - var right = goToPage("tutorialRight"); |
4488 | - var stage = findChild(right, "stage"); |
4489 | - var delegate0 = findChild(right, "appDelegate0"); |
4490 | - |
4491 | - tryCompare(stage, "dragProgress", 0); |
4492 | + tryCompare(tutorialLeft, "shown", false); |
4493 | + tryCompare(AccountsService, "demoEdgesCompleted", ["left"]); |
4494 | + } |
4495 | + |
4496 | + function test_tutorialLeftAutoSkipped() { |
4497 | + // Test that we skip the tutorial if user uses left edge themselves |
4498 | + |
4499 | + var tutorialLeft = findChild(shell, "tutorialLeft"); |
4500 | + LightDM.Greeter.showGreeter(); |
4501 | + tryCompare(tutorialLeft, "visible", false); |
4502 | + compare(AccountsService.demoEdgesCompleted, []); |
4503 | + |
4504 | + touchFlick(shell, 0, halfHeight, halfWidth, halfHeight); |
4505 | + tryCompare(AccountsService, "demoEdgesCompleted", ["left"]); |
4506 | + } |
4507 | + |
4508 | + function test_tutorialTopEdges() { |
4509 | + var tutorial = findChild(shell, "tutorial"); |
4510 | + var tutorialTop = findChild(tutorial, "tutorialTop"); |
4511 | + var launcher = findChild(shell, "launcher"); |
4512 | + var stage = findChild(shell, "stage"); |
4513 | + var panel = findChild(shell, "panel"); |
4514 | + |
4515 | + openTutorialTop(); |
4516 | + |
4517 | + tryCompare(tutorial, "running", true); |
4518 | + verify(!tutorial.launcherEnabled); |
4519 | + verify(!tutorial.spreadEnabled); |
4520 | + verify(tutorial.panelEnabled); |
4521 | + verify(tutorialTop.shown); |
4522 | + verify(!launcher.available); |
4523 | + verify(!stage.spreadEnabled); |
4524 | + verify(panel.indicators.available); |
4525 | + } |
4526 | + |
4527 | + function test_tutorialTopFinish() { |
4528 | + var tutorial = findChild(shell, "tutorial"); |
4529 | + var tutorialTop = findChild(tutorial, "tutorialTop"); |
4530 | + var panel = findChild(shell, "panel"); |
4531 | + |
4532 | + openTutorialTop(); |
4533 | + touchFlick(shell, halfWidth, 0, halfWidth, shell.height); |
4534 | + |
4535 | + tryCompare(tutorialTop, "shown", false); |
4536 | + tryCompare(AccountsService, "demoEdgesCompleted", ["left", "left-long", "top"]); |
4537 | + tryCompare(panel.indicators, "fullyOpened", true); |
4538 | + } |
4539 | + |
4540 | + function test_tutorialTopShortDrag() { |
4541 | + var tutorial = findChild(shell, "tutorial"); |
4542 | + var tutorialTop = findChild(tutorial, "tutorialTop"); |
4543 | + var panel = findChild(shell, "panel"); |
4544 | + |
4545 | + openTutorialTop(); |
4546 | + touchFlick(shell, halfWidth, 0, halfWidth, shell.height * 0.4, true, false); |
4547 | + // compare opacity with a bound rather than hard 0.6 because progress doesn't |
4548 | + // always match the drag perfectly (takes a moment for drag to kick in) |
4549 | + tryCompareFunction(function() { |
4550 | + return tutorialTop.opacity >= 0.6 && tutorialTop.opacity < 0.7; |
4551 | + }, true); |
4552 | + touchFlick(shell, halfWidth, 0, halfWidth, shell.height * 0.4, false, true); |
4553 | + |
4554 | + compare(tutorialTop.shown, true); |
4555 | + } |
4556 | + |
4557 | + function test_tutorialTopAutoSkipped() { |
4558 | + // Test that we skip the tutorial if user uses top edge themselves |
4559 | + |
4560 | + var tutorialLeftLoader = findChild(shell, "tutorialLeftLoader"); |
4561 | + var tutorialTop = findChild(shell, "tutorialTop"); |
4562 | + AccountsService.demoEdgesCompleted = ["left", "left-long"]; |
4563 | + tryCompare(tutorialLeftLoader, "active", false); |
4564 | + verify(!tutorialTop.shown); |
4565 | + |
4566 | + touchFlick(shell, halfWidth, 0, halfWidth, shell.height); |
4567 | + tryCompare(AccountsService, "demoEdgesCompleted", ["left", "left-long", "top"]); |
4568 | + } |
4569 | + |
4570 | + function test_tutorialRightEdges() { |
4571 | + var tutorial = findChild(shell, "tutorial"); |
4572 | + var tutorialRight = findChild(tutorial, "tutorialRight"); |
4573 | + var launcher = findChild(shell, "launcher"); |
4574 | + var stage = findChild(shell, "stage"); |
4575 | + var panel = findChild(shell, "panel"); |
4576 | + |
4577 | + openTutorialRight(); |
4578 | + |
4579 | + tryCompare(tutorial, "running", true); |
4580 | + verify(!tutorial.launcherEnabled); |
4581 | + verify(tutorial.spreadEnabled); |
4582 | + verify(!tutorial.panelEnabled); |
4583 | + verify(tutorialRight.shown); |
4584 | + verify(!launcher.available); |
4585 | + verify(stage.spreadEnabled); |
4586 | + verify(!panel.indicators.available); |
4587 | + } |
4588 | + |
4589 | + function test_tutorialRightFinish() { |
4590 | + var tutorial = findChild(shell, "tutorial"); |
4591 | + var tutorialRight = findChild(tutorial, "tutorialRight"); |
4592 | + var stage = findChild(shell, "stage"); |
4593 | + |
4594 | + openTutorialRight(); |
4595 | + touchFlick(shell, shell.width, halfHeight, 0, halfHeight); |
4596 | + |
4597 | + tryCompare(tutorialRight, "shown", false); |
4598 | + tryCompare(AccountsService, "demoEdgesCompleted", ["left", "left-long", "top", "right"]); |
4599 | + } |
4600 | + |
4601 | + function test_tutorialRightShortDrag() { |
4602 | + var tutorial = findChild(shell, "tutorial"); |
4603 | + var tutorialRight = findChild(tutorial, "tutorialRight"); |
4604 | + var stage = findChild(shell, "stage"); |
4605 | + |
4606 | + openTutorialRight(); |
4607 | touchFlick(shell, shell.width, halfHeight, shell.width * 0.8, halfHeight, true, false); |
4608 | - verify(stage.dragProgress > 0); |
4609 | - compare(stage.dragProgress, -delegate0.xTranslate); |
4610 | - touchFlick(shell, shell.width * 0.8, halfHeight, shell.width, halfHeight, false, true); |
4611 | - tryCompare(stage, "dragProgress", 0); |
4612 | - |
4613 | - tryCompare(delegate0, "x", shell.width); |
4614 | - |
4615 | - var screenshotImage = findChild(right, "screenshotImage"); |
4616 | - tryCompare(screenshotImage, "source", Qt.resolvedUrl("../../../qml/Tutorial/graphics/facebook.png")); |
4617 | - tryCompare(screenshotImage, "visible", true); |
4618 | - } |
4619 | - |
4620 | - function test_bottomShortDrag() { |
4621 | - var bottom = goToPage("tutorialBottom"); |
4622 | - |
4623 | - touchFlick(shell, halfWidth, shell.height, halfWidth, shell.height * 0.8); |
4624 | - |
4625 | - var errorTextLabel = findChild(bottom, "errorTextLabel"); |
4626 | - var errorTitleLabel = findChild(bottom, "errorTitleLabel"); |
4627 | - tryCompare(bottom, "shown", true); // still on bottom page |
4628 | - tryCompare(errorTextLabel, "opacity", 1); // show error |
4629 | - tryCompare(errorTitleLabel, "opacity", 1); // show error |
4630 | - } |
4631 | - |
4632 | - function test_interrupted() { |
4633 | - goToPage("tutorialLeft"); |
4634 | - ApplicationManager.startApplication("dialer-app"); |
4635 | - checkFinished(); |
4636 | + // compare opacity with a bound rather than hard 0.6 because progress doesn't |
4637 | + // always match the drag perfectly (takes a moment for drag to kick in) |
4638 | + tryCompareFunction(function() { |
4639 | + return tutorialRight.opacity >= 0.6 && tutorialRight.opacity < 0.8; |
4640 | + }, true); |
4641 | + touchFlick(shell, shell.width, halfHeight, shell.width * 0.8, halfHeight, false, true); |
4642 | + |
4643 | + compare(tutorialRight.shown, true); |
4644 | + } |
4645 | + |
4646 | + function test_tutorialRightDelay() { |
4647 | + // Test that if we exit the top tutorial, we don't immediately |
4648 | + // jump into right tutorial. |
4649 | + var tutorialRight = findChild(shell, "tutorialRight"); |
4650 | + var tutorialRightTimer = findInvisibleChild(tutorialRight, "tutorialRightInactivityTimer"); |
4651 | + |
4652 | + tutorialRightTimer.interval = 1; |
4653 | + openTutorialTop(); |
4654 | + ApplicationManager.startApplication("gallery-app"); |
4655 | + ApplicationManager.startApplication("facebook-webapp"); |
4656 | + tryCompare(ApplicationManager, "count", 3); |
4657 | + |
4658 | + AccountsService.demoEdgesCompleted = ["left", "left-long", "top"]; |
4659 | + verify(tutorialRightTimer.running, true); |
4660 | + verify(!tutorialRight.shown); |
4661 | + tryCompare(tutorialRight, "shown", true); |
4662 | + } |
4663 | + |
4664 | + function test_tutorialRightAutoSkipped() { |
4665 | + // Test that we skip the tutorial if user uses right edge themselves |
4666 | + |
4667 | + var tutorialLeftLoader = findChild(shell, "tutorialLeftLoader"); |
4668 | + AccountsService.demoEdgesCompleted = ["left", "left-long"]; |
4669 | + tryCompare(tutorialLeftLoader, "active", false); |
4670 | + |
4671 | + touchFlick(shell, shell.width, halfHeight, 0, halfHeight); |
4672 | + tryCompare(AccountsService, "demoEdgesCompleted", ["left", "left-long", "right"]); |
4673 | + } |
4674 | + |
4675 | + function test_tutorialBottomEdges() { |
4676 | + var tutorial = findChild(shell, "tutorial"); |
4677 | + var tutorialBottom = findChild(tutorial, "tutorialBottom"); |
4678 | + var tutorialLabel = findChild(tutorialBottom, "tutorialLabel"); |
4679 | + var launcher = findChild(shell, "launcher"); |
4680 | + var stage = findChild(shell, "stage"); |
4681 | + var panel = findChild(shell, "panel"); |
4682 | + |
4683 | + openTutorialBottom(); |
4684 | + |
4685 | + tryCompare(tutorial, "running", true); |
4686 | + verify(!tutorial.launcherEnabled); |
4687 | + verify(!tutorial.spreadEnabled); |
4688 | + verify(!tutorial.panelEnabled); |
4689 | + verify(tutorialBottom.shown); |
4690 | + verify(!launcher.available); |
4691 | + verify(!stage.spreadEnabled); |
4692 | + verify(!panel.indicators.available); |
4693 | + compare(tutorialLabel.text, "Swipe up for recent calls"); |
4694 | + } |
4695 | + |
4696 | + function test_tutorialBottomFinish() { |
4697 | + var tutorial = findChild(shell, "tutorial"); |
4698 | + var tutorialBottom = findChild(tutorial, "tutorialBottom"); |
4699 | + |
4700 | + openTutorialBottom(); |
4701 | + touchFlick(shell, halfWidth, shell.height, halfWidth, halfHeight); |
4702 | + |
4703 | + tryCompare(tutorialBottom, "shown", false); |
4704 | + tryCompare(AccountsService, "demoEdgesCompleted", ["left", "left-long", "top", "right", "bottom-dialer-app"]); |
4705 | + |
4706 | + // OK, we did one, just confirm that when all are done, we mark whole tutorial as done. |
4707 | + verify(AccountsService.demoEdges); |
4708 | + AccountsService.demoEdgesCompleted = ["left", "left-long", "top", "right", |
4709 | + "bottom-address-book-app", |
4710 | + "bottom-com.ubuntu.calculator_calculator", |
4711 | + "bottom-dialer-app", |
4712 | + "bottom-messaging-app"]; |
4713 | + verify(!AccountsService.demoEdges); |
4714 | + } |
4715 | + |
4716 | + function test_tutorialBottomAppearsBeforeRight() { |
4717 | + // Confirm that if bottom edge and right edge would appear on the |
4718 | + // the same app open, bottom edge appears first. (this is a lightly |
4719 | + // edited version of openTutorialRight) |
4720 | + var tutorialLeftLoader = findChild(shell, "tutorialLeftLoader"); |
4721 | + var tutorialRight = findChild(shell, "tutorialRight"); |
4722 | + var tutorialBottom = findChild(shell, "tutorialBottom"); |
4723 | + |
4724 | + AccountsService.demoEdgesCompleted = ["left", "left-long", "top"]; |
4725 | + ApplicationManager.startApplication("gallery-app"); |
4726 | + ApplicationManager.startApplication("dialer-app"); |
4727 | + |
4728 | + tryCompare(tutorialLeftLoader, "active", false); |
4729 | + tryCompare(tutorialBottom, "shown", true); |
4730 | + tryCompare(tutorialBottom, "opacity", 1); |
4731 | + tryCompare(tutorialRight, "visible", false); |
4732 | + } |
4733 | + |
4734 | + function test_tutorialBottomOnlyCoversSideStageOnTablet() { |
4735 | + loadShell("tablet"); |
4736 | + |
4737 | + var tutorialBottom = findChild(shell, "tutorialBottom"); |
4738 | + var targetHeight = shell.height - units.gu(4); |
4739 | + var mainStageX = units.gu(20); |
4740 | + var sideStageX = shell.width - units.gu(20); |
4741 | + |
4742 | + openTutorialBottom(); |
4743 | + |
4744 | + touchFlick(shell, mainStageX, shell.height, mainStageX, targetHeight, true, false); |
4745 | + compare(tutorialBottom.opacity, 1); |
4746 | + touchFlick(shell, mainStageX, shell.height, mainStageX, targetHeight, false, true); |
4747 | + |
4748 | + touchFlick(shell, sideStageX, shell.height, sideStageX, targetHeight, true, false); |
4749 | + verify(tutorialBottom.opacity < 1); |
4750 | + touchFlick(shell, sideStageX, shell.height, sideStageX, targetHeight, false, true); |
4751 | + } |
4752 | + |
4753 | + function test_tutorialBottomOnlyCoversMainStageOnTablet() { |
4754 | + loadShell("tablet"); |
4755 | + |
4756 | + var tutorialBottom = findChild(shell, "tutorialBottom"); |
4757 | + var targetHeight = shell.height - units.gu(4); |
4758 | + var mainStageX = units.gu(20); |
4759 | + var sideStageX = shell.width - units.gu(20); |
4760 | + |
4761 | + openTutorialBottom(); |
4762 | + var app = ApplicationManager.findApplication("dialer-app"); |
4763 | + app.setStage(ApplicationInfoInterface.MainStage); |
4764 | + |
4765 | + touchFlick(shell, sideStageX, shell.height, sideStageX, targetHeight, true, false); |
4766 | + compare(tutorialBottom.opacity, 1); |
4767 | + touchFlick(shell, sideStageX, shell.height, sideStageX, targetHeight, false, true); |
4768 | + |
4769 | + touchFlick(shell, mainStageX, shell.height, mainStageX, targetHeight, true, false); |
4770 | + verify(tutorialBottom.opacity < 1); |
4771 | + touchFlick(shell, mainStageX, shell.height, mainStageX, targetHeight, false, true); |
4772 | + } |
4773 | + |
4774 | + function test_activeCallInterruptsTutorial() { |
4775 | + var tutorialLeft = findChild(shell, "tutorialLeft"); |
4776 | + verify(tutorialLeft.shown); |
4777 | + verify(!tutorialLeft.paused); |
4778 | + |
4779 | + callManager.foregroundCall = phoneCall; |
4780 | + verify(!tutorialLeft.shown); |
4781 | + verify(tutorialLeft.paused); |
4782 | + tryCompare(tutorialLeft, "visible", false); |
4783 | + |
4784 | + callManager.foregroundCall = null; |
4785 | + tryCompare(tutorialLeft, "shown", true); |
4786 | + verify(!tutorialLeft.paused); |
4787 | + } |
4788 | + |
4789 | + function test_greeterInterruptsTutorial() { |
4790 | + var tutorialLeft = findChild(shell, "tutorialLeft"); |
4791 | + verify(tutorialLeft.shown); |
4792 | + verify(!tutorialLeft.paused); |
4793 | + |
4794 | + LightDM.Greeter.showGreeter(); |
4795 | + verify(!tutorialLeft.shown); |
4796 | + verify(tutorialLeft.paused); |
4797 | + tryCompare(tutorialLeft, "visible", false); |
4798 | + |
4799 | + LightDM.Greeter.hideGreeter(); |
4800 | + tryCompare(tutorialLeft, "shown", true); |
4801 | + verify(!tutorialLeft.paused); |
4802 | + } |
4803 | + |
4804 | + function test_interruptionChecksReadyStateWhenDone() { |
4805 | + // If we're done with an interruption (like active call), make sure |
4806 | + // that we don't blindly resume the tutorial -- our trigger |
4807 | + // conditions still need to be met. For example, there need to be |
4808 | + // enough apps open for the right edge tutorial. |
4809 | + |
4810 | + openTutorialRight(); |
4811 | + |
4812 | + var tutorialRight = findChild(shell, "tutorialRight"); |
4813 | + verify(tutorialRight.isReady); |
4814 | + verify(tutorialRight.shown); |
4815 | + verify(!tutorialRight.paused); |
4816 | + |
4817 | + callManager.foregroundCall = phoneCall; |
4818 | + killApps(); |
4819 | + callManager.foregroundCall = null; |
4820 | + |
4821 | + verify(!tutorialRight.isReady); |
4822 | + verify(!tutorialRight.shown); |
4823 | + verify(!tutorialRight.paused); |
4824 | + compare(AccountsService.demoEdgesCompleted, ["left", "left-long", "top"]); |
4825 | + } |
4826 | + |
4827 | + function test_desktopOnlyShowsTutorialRight() { |
4828 | + loadShell("desktop"); |
4829 | + |
4830 | + var tutorialLeftLoader = findChild(shell, "tutorialLeftLoader"); |
4831 | + var tutorialTopLoader = findChild(shell, "tutorialTopLoader"); |
4832 | + var tutorialRightLoader = findChild(shell, "tutorialRightLoader"); |
4833 | + var tutorialBottomLoader = findChild(shell, "tutorialBottomLoader"); |
4834 | + verify(!tutorialLeftLoader.active); |
4835 | + verify(!tutorialTopLoader.active); |
4836 | + verify(tutorialRightLoader.active); |
4837 | + verify(!tutorialBottomLoader.active); |
4838 | + compare(AccountsService.demoEdgesCompleted, []); |
4839 | + |
4840 | + ApplicationManager.startApplication("dialer-app"); |
4841 | + ApplicationManager.startApplication("camera-app"); |
4842 | + tryCompare(tutorialRightLoader.item, "isReady", true); |
4843 | + tryCompare(tutorialRightLoader, "shown", true); |
4844 | + } |
4845 | + |
4846 | + function test_oskDoesNotHideTutorial() { |
4847 | + var tutorialLeft = findChild(shell, "tutorialLeft"); |
4848 | + verify(tutorialLeft.shown); |
4849 | + |
4850 | + var surface = SurfaceManager.inputMethodSurface; |
4851 | + surface.setState(Mir.RestoredState); |
4852 | + |
4853 | + var inputMethod = findInvisibleChild(shell, "inputMethod"); |
4854 | + tryCompare(inputMethod, "state", "shown"); |
4855 | + |
4856 | + verify(tutorialLeft.shown); |
4857 | + } |
4858 | + |
4859 | + function test_oskPreventsTutorial() { |
4860 | + var surface = SurfaceManager.inputMethodSurface; |
4861 | + var inputMethod = findInvisibleChild(shell, "inputMethod"); |
4862 | + |
4863 | + AccountsService.demoEdges = false; |
4864 | + surface.setState(Mir.RestoredState); |
4865 | + tryCompare(inputMethod, "state", "shown"); |
4866 | + |
4867 | + var tutorial = findChild(shell, "tutorial"); |
4868 | + tryCompare(tutorial, "keyboardVisible", true); |
4869 | + |
4870 | + AccountsService.demoEdges = true; |
4871 | + var tutorialLeft = findChild(shell, "tutorialLeft"); |
4872 | + verify(!tutorialLeft.shown); |
4873 | + |
4874 | + surface.setState(Mir.MinimizedState); |
4875 | + tryCompare(inputMethod, "state", "hidden"); |
4876 | + tryCompare(tutorialLeft, "shown", false); |
4877 | + } |
4878 | + |
4879 | + function test_accountsServiceSettings() { |
4880 | + var tutorialLeft = findChild(shell, "tutorialLeft"); |
4881 | + verify(tutorialLeft != null); |
4882 | + verify(tutorialLeft.shown); |
4883 | + |
4884 | + AccountsService.demoEdges = false; |
4885 | + verify(findChild(shell, "tutorialLeft") == null); |
4886 | + |
4887 | + AccountsService.demoEdges = true; |
4888 | + tutorialLeft = findChild(shell, "tutorialLeft"); |
4889 | + verify(tutorialLeft != null); |
4890 | + tryCompare(tutorialLeft, "shown", true); |
4891 | } |
4892 | } |
4893 | } |
4894 | |
4895 | === modified file 'tests/qmltests/tst_Shell.qml' |
4896 | --- tests/qmltests/tst_Shell.qml 2016-03-10 22:43:31 +0000 |
4897 | +++ tests/qmltests/tst_Shell.qml 2016-03-15 20:13:37 +0000 |
4898 | @@ -131,6 +131,9 @@ |
4899 | anchors.right: root.right |
4900 | width: units.gu(30) |
4901 | |
4902 | + property var focusedApp: ApplicationManager.findApplication(ApplicationManager.focusedApplicationId) |
4903 | + property var focusedSurface: focusedApp && focusedApp.session ? focusedApp.session.lastSurface : null |
4904 | + |
4905 | Rectangle { |
4906 | id: controlRect |
4907 | anchors { left: parent.left; right: parent.right } |
4908 | @@ -251,6 +254,65 @@ |
4909 | appId: modelData |
4910 | } |
4911 | } |
4912 | + |
4913 | + Label { text: "Focused Application"; font.bold: true } |
4914 | + |
4915 | + Row { |
4916 | + CheckBox { |
4917 | + id: fullscreeAppCheck |
4918 | + |
4919 | + onTriggered: { |
4920 | + if (!controls.focusedSurface) return; |
4921 | + if (controls.focusedSurface.state == Mir.FullscreenState) { |
4922 | + controls.focusedSurface.state = Mir.RestoredState; |
4923 | + } else { |
4924 | + controls.focusedSurface.state = Mir.FullscreenState; |
4925 | + } |
4926 | + } |
4927 | + |
4928 | + Binding { |
4929 | + target: fullscreeAppCheck |
4930 | + when: controls.focusedSurface |
4931 | + property: "checked" |
4932 | + value: { |
4933 | + if (!controls.focusedSurface) return false; |
4934 | + return controls.focusedSurface.state === Mir.FullscreenState |
4935 | + } |
4936 | + } |
4937 | + } |
4938 | + Label { |
4939 | + text: "Fullscreen" |
4940 | + } |
4941 | + } |
4942 | + |
4943 | + Row { |
4944 | + CheckBox { |
4945 | + id: chromeAppCheck |
4946 | + |
4947 | + onTriggered: { |
4948 | + if (!controls.focusedSurface) return; |
4949 | + if (controls.focusedSurface.shellChrome == Mir.LowChrome) { |
4950 | + controls.focusedSurface.setShellChrome(Mir.NormalChrome); |
4951 | + } else { |
4952 | + controls.focusedSurface.setShellChrome(Mir.LowChrome); |
4953 | + } |
4954 | + } |
4955 | + |
4956 | + Binding { |
4957 | + target: chromeAppCheck |
4958 | + when: controls.focusedSurface !== null |
4959 | + property: "checked" |
4960 | + value: { |
4961 | + if (!controls.focusedSurface) return false; |
4962 | + controls.focusedSurface.shellChrome === Mir.LowChrome |
4963 | + } |
4964 | + } |
4965 | + } |
4966 | + Label { |
4967 | + text: "Low Chrome" |
4968 | + } |
4969 | + } |
4970 | + |
4971 | } |
4972 | } |
4973 | } |
4974 | @@ -425,6 +487,7 @@ |
4975 | setLightDMMockMode("single"); // back to the default value |
4976 | |
4977 | AccountsService.demoEdges = false; |
4978 | + AccountsService.demoEdgesCompleted = []; |
4979 | Wizard.System.wizardEnabled = false; |
4980 | |
4981 | // kill all (fake) running apps |
4982 | @@ -576,9 +639,8 @@ |
4983 | |
4984 | function test_tabletLeftEdgeDrag_data() { |
4985 | return [ |
4986 | - {tag: "without password", user: "no-password", loggedIn: true, demo: false}, |
4987 | - {tag: "with password", user: "has-password", loggedIn: false, demo: false}, |
4988 | - {tag: "with demo", user: "has-password", loggedIn: true, demo: true}, |
4989 | + {tag: "without password", user: "no-password", loggedIn: true}, |
4990 | + {tag: "with password", user: "has-password", loggedIn: false}, |
4991 | ] |
4992 | } |
4993 | |
4994 | @@ -588,10 +650,6 @@ |
4995 | |
4996 | selectUser(data.user) |
4997 | |
4998 | - AccountsService.demoEdges = data.demo |
4999 | - var tutorial = findChild(shell, "tutorial"); |
5000 | - tryCompare(tutorial, "running", data.demo); |
<dandrader> mterry, DDA changes in lp:~mterry/unity8/tutorial-redesign look fine
<mterry> dandrader, awesome, thanks
will quote you in the MP :)
<dandrader> mterry, only unsure about the property name. Because it will work all the same, only difference is that it won't claim ownership over the touch point once it recognizes it's performing a gesture
<mterry> dandrader, yeah. I'm happy to rename it. Got something you like better?
<dandrader> mterry, no :)