Merge lp:~mzanetti/unity8/right-edge-2 into lp:unity8
- right-edge-2
- Merge into trunk
Status: | Superseded | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Proposed branch: | lp:~mzanetti/unity8/right-edge-2 | ||||||||||||
Merge into: | lp:unity8 | ||||||||||||
Diff against target: |
4317 lines (+2412/-902) 43 files modified
debian/control (+3/-1) debian/unity8.install (+1/-1) plugins/Utils/CMakeLists.txt (+2/-1) plugins/Utils/easingcurve.cpp (+67/-0) plugins/Utils/easingcurve.h (+70/-0) plugins/Utils/plugin.cpp (+2/-0) qml/CMakeLists.txt (+1/-1) qml/Components/ApplicationManagerWrapper.qml (+0/-169) qml/Components/ApplicationScreenshot.qml (+0/-61) qml/Components/ApplicationsModelStageFiltered.qml (+0/-49) qml/Components/ResponsiveFlowView.qml (+3/-10) qml/Dash/Apps/RunningApplicationTile.qml (+15/-25) qml/Dash/Apps/RunningApplicationsGrid.qml (+5/-20) qml/Dash/DashApps.qml (+4/-5) qml/Dash/GenericScopeView.qml (+2/-2) qml/Launcher/Launcher.qml (+2/-1) qml/Panel/Panel.qml (+1/-1) qml/Shell.qml (+229/-331) qml/SideStage/SideStage.qml (+0/-73) qml/Stages/PhoneStage.qml (+501/-0) qml/Stages/SpreadDelegate.qml (+55/-0) qml/Stages/StageWithSideStage.qml (+405/-0) qml/Stages/SwitchingApplicationImage.qml (+81/-0) qml/Stages/TransformedSpreadDelegate.qml (+327/-0) run_on_device (+1/-0) tests/autopilot/unity8/shell/emulators/dash.py (+1/-8) tests/autopilot/unity8/shell/emulators/main_window.py (+1/-1) tests/autopilot/unity8/shell/tests/test_emulators.py (+1/-1) tests/mocks/Unity/Application/ApplicationInfo.cpp (+9/-0) tests/mocks/Unity/Application/ApplicationInfo.h (+2/-0) tests/mocks/Unity/Application/ApplicationManager.cpp (+109/-3) tests/mocks/Unity/Application/ApplicationManager.h (+16/-0) tests/mocks/Unity/Application/ApplicationScreenshotProvider.cpp (+74/-0) tests/mocks/Unity/Application/ApplicationScreenshotProvider.h (+34/-0) tests/mocks/Unity/Application/CMakeLists.txt (+1/-0) tests/mocks/Unity/Application/plugin.cpp (+18/-3) tests/mocks/Unity/Application/plugin.h (+1/-0) tests/plugins/Unity/Launcher/launchermodeltest.cpp (+5/-0) tests/qmltests/CMakeLists.txt (+1/-1) tests/qmltests/Components/tst_ResponsiveFlowView.qml (+1/-2) tests/qmltests/Dash/Apps/tst_RunningApplicationsGrid.qml (+57/-124) tests/qmltests/Stages/tst_PhoneStage.qml (+288/-0) tests/qmltests/tst_Shell.qml (+16/-8) |
||||||||||||
To merge this branch: | bzr merge lp:~mzanetti/unity8/right-edge-2 | ||||||||||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Gerry Boland (community) | Approve | ||
Mirco Müller (community) | Approve | ||
PS Jenkins bot (community) | continuous-integration | Needs Fixing | |
Albert Astals Cid (community) | Needs Fixing | ||
Ubuntu Unity PS integration team | packaging | Pending | |
Vesa Rautiainen | Pending | ||
Review via email: mp+204798@code.launchpad.net |
This proposal has been superseded by a proposal from 2014-03-28.
Commit message
Implement the right edge app switching with an App Spread.
* Reworks interaction with ApplicationManager (This will end SurfaceFlinger support)
* Reworks Stage and SideStage
* Implements the App Spread for the Phone form factor right edge
* Reimplements the overlay mode side stage for the tablet form factor
Description of the change
* Are there any related MPs required for this MP to build/function as expected? Please list.
https:/
https:/
https:/
https:/
https:/
Here are packages for everything related: https:/
* Did you perform an exploratory manual test run of your code change and any related functionality?
Yes (MWC image)
* If you changed the packaging (debian), did you subscribe the ubuntu-unity team to this MP?
Yes
* If you changed the UI, has there been a design review?
lots of them :)
- 660. By Michael Zanetti
-
drop print()s
- 661. By Michael Zanetti
-
add missing copyright headers
- 662. By Michael Zanetti
-
drop old sidestage code
- 663. By Michael Zanetti
-
drop prints()s in StageWithSideStage
PS Jenkins bot (ps-jenkins) wrote : | # |
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:663
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 664. By Michael Zanetti
-
add missing copyright headers
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:664
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 665. By Michael Zanetti
-
ooops. Add missing files
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:665
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 666. By Michael Zanetti
-
make it start up in phone form factor again
- 667. By Michael Zanetti
-
merge trunk
Daniel d'Andrada (dandrader) wrote : | # |
1785 +// Rectangle { anchors.fill: parent; color: "blue"; opacity: 0.5 }
Leftover
Daniel d'Andrada (dandrader) wrote : | # |
1901 + onApplicationAdded: {
1902 + priv.startingAppId = appId;
1903 +// var application = ApplicationMana
1904 +// print("Application added:", appId, application.state)
1905 +// if (application.stage == ApplicationInfo
1906 +// priv.sideStageAppId = appId;
1907 +// mainStageImage.
1908 +// mainStageImage.
1909 +// } else if (application.stage == ApplicationInfo
1910 +// priv.mainStageAppId = appId;
1911 +// sideStageImage.
1912 +// sideStageImage.
1913 +// }
1914 + }
Do we want to have this commented-out code?
- 668. By Michael Zanetti
-
remove leftover Rectangle
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:667
http://
Executed test runs:
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 : | # |
FAILED: Continuous integration, rev:668
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 669. By Michael Zanetti
-
update according to latest unity-api changes
- 670. By Michael Zanetti
-
also update launchertest's mocked appmanager to the new api
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:669
http://
Executed test runs:
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 : | # |
FAILED: Continuous integration, rev:670
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 671. By Michael Zanetti
-
fix whitespace tests
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:671
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Gerry Boland (gerboland) wrote : | # |
Please mention in the commit message that this branch marks the end of SurfaceFlinger support, so unity8 is not Mir only.
Gerry Boland (gerboland) wrote : | # |
> Please mention in the commit message that this branch marks the end of
> SurfaceFlinger support, so unity8 is not Mir only.
I meant: *now* Mir only
/hittip tsdgeos
Daniel d'Andrada (dandrader) wrote : | # |
In PhoneStage.qml:
"""
+ property bool fullscreen: ApplicationMana
"""
That generates errors, polluting the console, when there's no focused application. Having it the following way is more concise and solves this issue:
property bool fullscreen: priv.focusedApp
Daniel d'Andrada (dandrader) wrote : | # |
Likewise here:
"""
"""
Daniel d'Andrada (dandrader) wrote : | # |
I'm getting the following error on start up:
qml/Stages/
Which is solved by:
"""
id: snapAnimation
- property int targetContentX: -shift
+ property int targetContentX: -spreadView.shift
"""
Gerry Boland (gerboland) wrote : | # |
+++ qml/Shell.qml
+ property bool sideStageEnabled: shell.width >= units.gu(60)
Can be readonly.
+ property bool fullyCovered: panel.indicator
Do no harm here either
Daniel d'Andrada (dandrader) wrote : | # |
And this other error on start up:
qml/Stages/
"""
"""
So gotta check if there's indeed a running app before querying its screenshot.
Gerry Boland (gerboland) wrote : | # |
+ readonly property bool applicationRunning: ApplicationMana
I don't see this used anywhere actually.
Gerry Boland (gerboland) wrote : | # |
Functional bugs (phone testing only)
1. I launch Contacts app from dash. Wait for it to appear. Left edge swipe it away. I'm not able to bring back Contacts by tapping its preview, nor its dahs or launcher icon.
2. I launch Contacts app from dash. Wait for it to appear. Left edge swipe it away. I then launch Dialer app from dash, I don't get a starting animation: instead Contacts app immediately shown, and eventually Dialer pops up on top
Gerry Boland (gerboland) wrote : | # |
3. With 2 apps open, doing a full right edge swipe, the animation is linked to my finger distance from the right edge, until about 70% of the way, when it just stops. Then only finger release completes the animation. It feels like the animation locks up. Did Design want this?
4. Have app open and active. Press power to turn off display, and again to show greeter. Do a slow right-edge swipe - a black rectangle is revealed. Only on finger release does the app appear.
5. I've 2 apps open. I open a third from the dash. Once it has appeared (giving it a second more just in case), I start a right edge gesture. I only see 2 apps in the spread, the latest one has disappeared
Gerry Boland (gerboland) wrote : | # |
Sorry about the hopeless picture, but this was something minor I noticed:
http://
I opened 3 apps, dialer, contacts & system settings. With the order in the spread of contacts, settings, dialer, I grabbed the dialer screenshot and brought it as far left as I could. I noticed that a bit of the system settings image could be made visible over the dialer. See the image above, I marked it in red
Gerry Boland (gerboland) wrote : | # |
6. With spread open, opening launcher and tapping dash icon does nothing
7. Have a couple of apps open, and engage the spread. Now open the (as example) sound indicator, and tap the "Sound settings" entry. Indicators close, but spread remains. Tapping the system settings does bring me to the correct screen.
8. Strangely, if I open System Settings app via indicators (same steps as in 7 above), it often opens with incorrect x position of the surface (i.e there's a 2-3GU gap on the left). Need to check with trunk.
Gerry Boland (gerboland) wrote : | # |
9. Have system settings & dialer app open, dialer app to the front. Open indicators, select Sound and tap "Sound settings". You see the dialer app slide to the right, but a black rectangle remains, until suddenly system settings appears
Gerry Boland (gerboland) wrote : | # |
http://
Gerry Boland (gerboland) wrote : | # |
> http://
Ah I had started Gmail app. Seems it took an ultra long time to start up, so appeared in the running apps list, but no screenshot for it existed?? So the delegate was too narrow?
Gerry Boland (gerboland) wrote : | # |
10. Starting Gallery app does not make panel hide (which it should)
11. Quick right edge swipe can be a little flickery. I'd forgive this however, I know what's going on.
12. With multiple apps open, bring up the OSK somehow. Then do right edge swipe to show spread. OSK stuck open
Gerry Boland (gerboland) wrote : | # |
13. seems running apps icons are not all the same width: http://
Gerry Boland (gerboland) wrote : | # |
Question: in the spread, the edges of the transformed screenshots are not antialiased. Turning on smoothing bad?
Gerry Boland (gerboland) wrote : | # |
14. this is a tricky one to reproduce: open like 8+ apps. Right edge to open spread. Flick list to the left so you see top-most screenshot. Now flick it again, and while it is bouncing, do a right-edge swipe. When I do this, I switch to the second last app in the list (like the quick right-edge Alt-Tab swipe)
Gerry Boland (gerboland) wrote : | # |
nitpick: with 8+ apps open, when you flick spread to the the left, so you see top-most screenshot, the framerate drops a bit. Optimisation can be left for later naturally
Gerry Boland (gerboland) wrote : | # |
15. with spread open (3+ apps running), a long left swipe causes launcher to open, then close again. Would be better if it stayed open IMO. Short left swipe open it fine
Michael Zanetti (mzanetti) wrote : | # |
> > Please mention in the commit message that this branch marks the end of
> > SurfaceFlinger support, so unity8 is not Mir only.
> I meant: *now* Mir only
> /hittip tsdgeos
done
- 672. By Michael Zanetti
-
add some comments to EasingCurve
- 673. By Michael Zanetti
-
merge trunk
- 674. By Michael Zanetti
-
get rid of warning in case there is no fullscreen app
Michael Zanetti (mzanetti) wrote : | # |
> In PhoneStage.qml:
>
> """
> + property bool fullscreen: ApplicationMana
> ger.focusedAppl
> """
>
> That generates errors, polluting the console, when there's no focused
> application. Having it the following way is more concise and solves this
> issue:
>
> property bool fullscreen: priv.focusedApp
> priv.focusedApp
done
- 675. By Michael Zanetti
-
get rid of another wanring that may happen in some certain circumstances
Michael Zanetti (mzanetti) wrote : | # |
> Likewise here:
>
> """
> PropertyAction { target: fadeInScreensho
> value: ApplicationMana
> """
done
- 676. By Michael Zanetti
-
make it initialize correctly
Michael Zanetti (mzanetti) wrote : | # |
> I'm getting the following error on start up:
>
> qml/Stages/
>
> Which is solved by:
>
> """
> SequentialAnimation {
> id: snapAnimation
> - property int targetContentX: -shift
> + property int targetContentX: -spreadView.shift
>
> UbuntuNumberAni
> target: spreadView
> """
Dammit. I fixed this already and forgot to push it to this branch... Too many branches floating around right now. Thanks for pointing out!
fixed.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:674
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 677. By Michael Zanetti
-
activateApplication -> requestFocusApp
lication as per unity-api definition
Michael Zanetti (mzanetti) wrote : | # |
> Functional bugs (phone testing only)
> 1. I launch Contacts app from dash. Wait for it to appear. Left edge swipe it
> away. I'm not able to bring back Contacts by tapping its preview, nor its dahs
> or launcher icon.
>
> 2. I launch Contacts app from dash. Wait for it to appear. Left edge swipe it
> away. I then launch Dialer app from dash, I don't get a starting animation:
> instead Contacts app immediately shown, and eventually Dialer pops up on top
Both were caused because unity8 still called activateApplica
Both fixed.
- 678. By Michael Zanetti
-
reenable workaround timer
Michael Zanetti (mzanetti) wrote : | # |
> > Functional bugs (phone testing only)
> > 1. I launch Contacts app from dash. Wait for it to appear. Left edge swipe
> it
> > away. I'm not able to bring back Contacts by tapping its preview, nor its
> dahs
> > or launcher icon.
> >
> > 2. I launch Contacts app from dash. Wait for it to appear. Left edge swipe
> it
> > away. I then launch Dialer app from dash, I don't get a starting animation:
> > instead Contacts app immediately shown, and eventually Dialer pops up on top
>
> Both were caused because unity8 still called activateApplica
> changed to reqeastFocusApp
>
> Both fixed.
Sorry #2 was something else. I disabled one of the screenshotting workarounds in order to be faster writing the tests and forgot to reenable it back. Now both fixed for real.
- 679. By Michael Zanetti
-
remove unused leftover property
Michael Zanetti (mzanetti) wrote : | # |
> + readonly property bool applicationRunning:
> ApplicationMana
> I don't see this used anywhere actually.
correct. removed it
- 680. By Michael Zanetti
-
don't disable the spread for 2 running apps
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:677
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 681. By Michael Zanetti
-
resume app immediately when the user starts moving the greeter, otherwise it won't paint anything
Michael Zanetti (mzanetti) wrote : | # |
> 3. With 2 apps open, doing a full right edge swipe, the animation is linked to
> my finger distance from the right edge, until about 70% of the way, when it
> just stops. Then only finger release completes the animation. It feels like
> the animation locks up. Did Design want this?
Turns out the spread shouldn't be disabled at all if there are only 2 apps. => fixed.
>
> 4. Have app open and active. Press power to turn off display, and again to
> show greeter. Do a slow right-edge swipe - a black rectangle is revealed. Only
> on finger release does the app appear.
Fixed. good catch. The app was still suspended by ApplicationMana
>
> 5. I've 2 apps open. I open a third from the dash. Once it has appeared
> (giving it a second more just in case), I start a right edge gesture. I only
> see 2 apps in the spread, the latest one has disappeared
Caused by a dumb mistake in the latest unity-mir change. fixed, updated pacakges will show up on chinstrap soon.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:681
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Michael Zanetti (mzanetti) wrote : | # |
> 13. seems running apps icons are not all the same width:
> http://
> Note that not all apps are fullscreen any more.
Hmm... True. That's because they keep their aspect ratio now. I could wrap then in an Item to keep them aligned but that would look quite bad in the tablet scenario where portrait and landscape apps mixed in this view. Not really sure how to deal with this tbh. Any suggestions?
- 682. By Michael Zanetti
-
make the topMargin follow the same easing curve as the rest
Michael Zanetti (mzanetti) wrote : | # |
> Sorry about the hopeless picture, but this was something minor I noticed:
> http://
> I opened 3 apps, dialer, contacts & system settings. With the order in the
> spread of contacts, settings, dialer, I grabbed the dialer screenshot and
> brought it as far left as I could. I noticed that a bit of the system settings
> image could be made visible over the dialer. See the image above, I marked it
> in red
fixed.
- 683. By Michael Zanetti
-
fix home button not working while in spread mode
- 684. By Michael Zanetti
-
drop print
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:682
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 685. By Michael Zanetti
-
fix tiny animation mismatch after adjusting the topMargin scaling to do an easingcurve instead of being linear
- 686. By Michael Zanetti
-
some fixes if apps are activated from outside the spread while we're in spread mode
Michael Zanetti (mzanetti) wrote : | # |
> 6. With spread open, opening launcher and tapping dash icon does nothing
fixed.
>
> 7. Have a couple of apps open, and engage the spread. Now open the (as
> example) sound indicator, and tap the "Sound settings" entry. Indicators
> close, but spread remains. Tapping the system settings does bring me to the
> correct screen.
Should be fixed now.
>
> 8. Strangely, if I open System Settings app via indicators (same steps as in 7
> above), it often opens with incorrect x position of the surface (i.e there's a
> 2-3GU gap on the left). Need to check with trunk.
hmm... quite unlikely this has anything to do with this branches. the misplaced surface is the real app surface whereas this branch only deals with screenshots which are placed correctly.
Michael Zanetti (mzanetti) wrote : | # |
> 9. Have system settings & dialer app open, dialer app to the front. Open
> indicators, select Sound and tap "Sound settings". You see the dialer app
> slide to the right, but a black rectangle remains, until suddenly system
> settings appears
This is the default app starting white rectangle which will eventually be replaced by a splash screen I believe, but a bit out of scope of this branch imo.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:685
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 687. By Michael Zanetti
-
fix panel not always hiding when it should
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:686
http://
Executed test runs:
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 : | # |
FAILED: Continuous integration, rev:687
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Daniel d'Andrada (dandrader) wrote : | # |
The problem handles by spreadDragArea's code (collecting gesturePoints, etc) looks remarkably like what EdgeDragEvaluator does. Have you considered using it before you went with this implementation?
Daniel d'Andrada (dandrader) wrote : | # |
> The problem handles by spreadDragArea's code (collecting gesturePoints, etc)
> looks remarkably like what EdgeDragEvaluator does. Have you considered using
> it before you went with this implementation?
Look how DragHandle uses it.
Michael Zanetti (mzanetti) wrote : | # |
> 10. Starting Gallery app does not make panel hide (which it should)
Fixed.
>
> 11. Quick right edge swipe can be a little flickery. I'd forgive this however,
> I know what's going on.
Hmm... seems to work perfectly fine here... But I guess if you flick really quick and the device is busy otherwise you might manage to see some screenshot updating action.
>
> 12. With multiple apps open, bring up the OSK somehow. Then do right edge
> swipe to show spread. OSK stuck open
Yeah... that's a bit of an issue. Right now there's no way to hide the OSK except unfocing the app. As that causes the whole state machine to update it causes effects like the panel coming in for half a second (you you transition from fullscreen to fullscreen) and some more such issues. Changing the code to deal with that would be quite intrusive and afaik the plan is to make the OSK part of the app surface anyways. Can we ignore this for this merge?
- 688. By Michael Zanetti
-
enable antialiasing on spread tiles
Michael Zanetti (mzanetti) wrote : | # |
> Question: in the spread, the edges of the transformed screenshots are not
> antialiased. Turning on smoothing bad?
I've enabled antialiasing on the tiles now. Doesn't seem to badly impact performance. Thanks for the hint. Didn't even know that property existed since QtQuick 2.0
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:688
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 689. By Michael Zanetti
-
Disabling DDA when Spread is in stage 2, now that DDA can handle being disabled while being dragged
Michael Zanetti (mzanetti) wrote : | # |
> 14. this is a tricky one to reproduce: open like 8+ apps. Right edge to open
> spread. Flick list to the left so you see top-most screenshot. Now flick it
> again, and while it is bouncing, do a right-edge swipe. When I do this, I
> switch to the second last app in the list (like the quick right-edge Alt-Tab
> swipe)
Ok, now that the DirectionalDragArea can handle being disabled while being used, I disabled it when entering stage 2. That prevents this from happening, however there's still a possibility to mess it a little up. If you quickly put down the Finger into the "empty" area while the Flickable overshoots and keep the finger there, the Flickable seems to get a mouseMove even, but releasing the finger now does not produce the mouseReleased event. If you now touch the flickable somewhere, it counts the distance as a movement and you can make it jump a bit before it follows the finger again. I'll try to improve it further but it doesn't seem as bad any more as before.
Michael Zanetti (mzanetti) wrote : | # |
> nitpick: with 8+ apps open, when you flick spread to the the left, so you see
> top-most screenshot, the framerate drops a bit. Optimisation can be left for
> later naturally
The thing is, if you open 8+ apps, the overall framerate drops. Just opening 8+ apps without even using the spread (or even in trunk) makes all animations (Launcher, Dash etc) become sluggish. AlbertA and Anpok have improved this a lot already (used to happen with 4+ apps a month ago) and I believe there's still some improvements upcoming (e.g. opaque surfaces).
While there might well be room for improvements in the Spread, I think this particular issue is rather Mir related.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:689
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Michael Zanetti (mzanetti) wrote : | # |
> > http://
> Ah I had started Gmail app. Seems it took an ultra long time to start up, so
> appeared in the running apps list, but no screenshot for it existed?? So the
> delegate was too narrow?
Yeah... There is still a little issue if you minimize an app before it paints on the screen for the first time. In that case we can't grab a screenshot. Current trunk has empty tiles in here which I guess is a bit better than this. Again, the fact that we're keeping the aspect ration here doesn't ease things up. But I can try to find a workaround for the time being (until we get rid of the screenshotting stuff) if you want me to.
Michael Zanetti (mzanetti) wrote : | # |
> > The problem handles by spreadDragArea's code (collecting gesturePoints, etc)
> > looks remarkably like what EdgeDragEvaluator does. Have you considered using
> > it before you went with this implementation?
>
> Look how DragHandle uses it.
As discussed on IRC, design wants this to complete the gesture if the user does a one-way flick but they explicitly said that the gesture speed should not have any impact on it. I'm struggling a bit to make the EdgeDragEvaluator do exactly that, so we agreed to keep it as is.
However, I'll bring up the topic of consistent edge gestures behavior (in terms of speed, distance and direction) in the next design meeting.
Albert Astals Cid (aacid) wrote : | # |
Doesn't merge with current unity8 trunk
Text conflict in plugins/
Text conflict in qml/Shell.qml
2 conflicts encountered.
- 690. By Michael Zanetti
-
merge trunk
Michael Zanetti (mzanetti) wrote : | # |
> Doesn't merge with current unity8 trunk
> Text conflict in plugins/
> Text conflict in qml/Shell.qml
> 2 conflicts encountered.
fixed
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:690
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Gerry Boland (gerboland) wrote : | # |
+ function hide() {
+ if (locked) {
+ return;
+ }
+ forceHide();
+ }
Why does hide not do anything if the spreadView is visible? Well more like, it sounds like an error that hide is called when spreadView is visible.
+ blockInput: ApplicationMana
Nitpick: checking length of the appId to be zero to prove there's no focused app? Not wrong, just reads a bit funny. Maybe String::isEmpty() works in QML, never tried it.
+ property string focusedAppId: ApplicationMana
+ property var focusedApplication: ApplicationMana
Just checking: the extra focusedAppId property needed to properly update the focusedApplication property? (you do this in a few places, so just curious why)
+++ qml/Stages/
+ onMovingChanged: {
...
+ } else {
+ mainScreenshotI
Maybe setting mainScreenshotI
+ Image {
+ id: mainScreenshotImage
+ property string src
+ source: src
why not just use source everywhere?
Gerry Boland (gerboland) wrote : | # |
General JS comment: sometimes you use semicolons, other times you don't. Think it better to just use them.
Gerry Boland (gerboland) wrote : | # |
+++ qml/Stages/
+ onFocusedApplic
+ var application = ApplicationMana
Might as well use priv.focusedApp
+ id: priv
+ property string focusedAppId: ApplicationMana
+ property var focusedApplication: ApplicationMana
+ property url focusedScreenshot: focusedApplication ? focusedApplicat
Times like these I wish QML properties were readonly by default, and you had to use a specifier to specify otherwise
+ onFocusedScreen
+ mainScreenshotI
mainScreenshotI
+ function requestNewScree
+ ApplicationMana
ApplicationMana
+ function indexOf(appId) {
I see why you need it, but not a giant fan of scanning the whole model for an index, just to reposition the spreadView. Not that I have a better idea however!
+ // FIXME: the signal connections seems to get lost.
+ // Check with Qt 5.2, see if we can remove this Connections and Binding objects
5.2 landed, fancy giving this a look?
+ // PropertyAction seems to fail when secondApplicati
+ ScriptAction { script: mainScreenshotI
+ spreadView.
Weird, I don't see why a PropertyAction would be incorrect here. Did you try setting a binding instead of a value, just as an experiment?
+ PropertyAction { target: fadeInScreensho
pity you need to search twice here, could you not store the value temporarily?
+ PropertyAction { target: fadeInScreensho
+ PropertyAction { target: mainScreenshotI
Fun fact: can replace this with
PropertyAction { targets: [fadeInScreensh
not a demand though, both ways are fine.
+ UbuntuNumberAni
+ UbuntuNumberAni
similarly, this can be
UbuntuNumberA
Gerry Boland (gerboland) wrote : | # |
Questions: there are 2 appSplash instances? Is that if user starts 2 apps quickly?
+ property bool attachedToView: true
a comment explaining this would be nice. In fact, the logic in the EdgeDragArea could do with the same.
+ if (oneWayFlick && spreadView.
please wrap that line a bit
+ property real positionMarker3: 0.6
+ property real positionMarker4: .9
Consistency please
+ // Stage of the animation:
+ property int stage: not a fan of the term, as "Stage" has a particular meaning for us. Would the Flickable's "States" system be useful here, as instead of numbers, can give the animation stages names?
+ onShiftedConten
+ case 1:
/me pedant, but adding "break" here too might spare a future coder some pain
+// duration: UbuntuAnimation
remove?
+ spreadView.stage = 4;
leftover?
+ if (spreadView.
what's going on here? floating point equality comparison makes me suspicious
+ id: spreadRow
+ width: Math.max(3, ApplicationMana
fancy maths could do with a comment explaining it :)
+++ qml/Stages/
+ anchors { left: parent.left; bottom: parent.bottom; top: parent.top; topMargin: priv.heightDiff
please wrap so topMargin is on its own line, as that's the nontrivial bit.
+ scale: 1
unnecessary, that's the default value.
Gerry Boland (gerboland) wrote : | # |
+++ qml/Stages/
How closely would you like me to review this? Since there's plenty of commented out lines and stuff, would you prefer a functional & code-sanity review only?
- 691. By Michael Zanetti
-
add comment and link to bug report
Michael Zanetti (mzanetti) wrote : | # |
> + function hide() {
> + if (locked) {
> + return;
> + }
> + forceHide();
> + }
> Why does hide not do anything if the spreadView is visible? Well more like, it
> sounds like an error that hide is called when spreadView is visible.
It's needed to be able to press the home button in the launcher and return to the dash even while the spread is visible. Usually something calling hide() in the shell should not be able to hide the spread with a few exceptions. The user pressing the home button in the launcher is one of them.
>
> + blockInput: ApplicationMana
> Nitpick: checking length of the appId to be zero to prove there's no focused
> app? Not wrong, just reads a bit funny. Maybe String::isEmpty() works in QML,
> never tried it.
No, isEmpty() doesn't work as it's not really a QString (QString is not a QObject). It's the JavaScript string class.
>
> + property string focusedAppId: ApplicationMana
> + property var focusedApplication:
> ApplicationMana
> Just checking: the extra focusedAppId property needed to properly update the
> focusedApplication property? (you do this in a few places, so just curious
> why)
No... One is not to properly update the other, but rather to have everything at hands in the surrounding code without having to call functions in ApplicationManager each time and reduce length of the code.
>
> +++ qml/Stages/
> + onMovingChanged: {
> ...
> + } else {
> + mainScreenshotI
> Maybe setting mainScreenshotI
> spread not open? Probably more GPU memory than system memory. It might have
> cost too though, so just an idea
>
That causes an issue: When you swipe the stage away with a left edge swipe and then pull it back in, this is the screenshot that is visible. If you think it's worth reworking this to unset and re-set the image for that case I'll do, but I'm not sure we should "polish" the screenshotting stuff that's supposed to go away.
> + Image {
> + id: mainScreenshotImage
> + property string src
> + source: src
> why not just use source everywhere?
There is a bug in our imageprovider. changing source does not emit sourceChanged.
https:/
I've added a FIXME comment with the link to the bug report.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:691
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 692. By Michael Zanetti
-
added missing ; at imperative line endings
Michael Zanetti (mzanetti) wrote : | # |
> General JS comment: sometimes you use semicolons, other times you don't. Think
> it better to just use them.
ack. added them.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:692
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Michael Zanetti (mzanetti) wrote : | # |
> +++ qml/Stages/
> How closely would you like me to review this? Since there's plenty of
> commented out lines and stuff, would you prefer a functional & code-sanity
> review only?
Yeah, this is really the part that's subject to be reworked when the right edge animation for the tablet comes in. So all I'd ask you to do here is to check out if its "good enough" to not totally break the tablet experience. It definitely has issues.
Gerry Boland (gerboland) wrote : | # |
+++ qml/Stages/
+ onApplicationCh
debug info necessary?
+ signal switched()
I prefer roughly sticking to the guidelines (http://
+ Image {
+ visible: true
should not be necessary
You have a couple of commented out lines in this file too, please remove them.
Gerry Boland (gerboland) wrote : | # |
+++ qml/Stages/
Since this relies heavily on the animation "stages" reported by the spreadView, a comment explaining the different behaviours of the tile in each stage (mentioning the position markers) would help a lot.
+ property real animatedProgress: 0
purpose not obvious to me how it's different to "progress", add comment please
+ property real tile1StartScale: startScale + .4
+ property real tile0SnapAngle: 10
could be made readonly, or private actually.
+ priv.stage2star
confuses me, why the -spreadView.width offset for the animation?
+ // As they are static values, lets caluclate
typo
+ property real xTranslate: {
in many of the calculations in this block, there's a "-spreadView.width" being used in the calculation of the start or end value in a linearAnimation. Could you add a note justifying it?
+ return linearAnimation
please wrap
+ } else if(spreadView.stage == 1) {
space needed after "if"
Gerry Boland (gerboland) wrote : | # |
+++ tests/mocks/
- ,m_state(Starting)
+ ,m_state(Running)
looks wrong to me, why would an app start immediately in a "running" state. Real AppMan does not do that.
+++ tests/mocks/
+#include <QDebug>
not needed
+++ tests/mocks/
do we need the qDebugs?
Gerry Boland (gerboland) wrote : | # |
+++ tests/mocks/
+ * Copyright (C) 2013 Canonical, Ltd.
2014
+ if (app == NULL) {
nullptr
+ QGuiApplication *unity = qobject_
can go inside the else block where it's actually used. Quick comment explaining what's going on would be handy too for the causal reader (you're scaling the image the the width of the window for all main stage apps).
qDebug needed?
Gerry Boland (gerboland) wrote : | # |
+++ tests/mocks/
+ * Copyright (C) 2013 Canonical, Ltd.
2014
- 693. By Michael Zanetti
-
fix nasty issue that appeard with Qt 5.2 (was bad code already, just happened to work for 5.0)
- 694. By Michael Zanetti
-
use existing property instead of doing the function call again
- 695. By Michael Zanetti
-
make some props readonly
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:693
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Michael Zanetti (mzanetti) wrote : | # |
> +++ qml/Stages/
> + onFocusedApplic
> + var application =
> ApplicationMana
> Might as well use priv.focusedApp
yes. fixed.
>
> + id: priv
> + property string focusedAppId: ApplicationMana
> + property var focusedApplication:
> ApplicationMana
> + property url focusedScreenshot: focusedApplication ?
> focusedApplicat
> Times like these I wish QML properties were readonly by default, and you had
> to use a specifier to specify otherwise
Hmm... due to a workaround for something I believe is a bug in Qt/QML I need to write them. Besides its not public API so I don't think its much of an issue.
>
> + onFocusedScreen
> + mainScreenshotI
> ger.focusedAppl
> mainScreenshotI
yep. fixed.
>
> + function requestNewScree
> +
> ApplicationMana
> ApplicationMana
fixed
> + function indexOf(appId) {
> I see why you need it, but not a giant fan of scanning the whole model for an
> index, just to reposition the spreadView. Not that I have a better idea
> however!
Hmm... This is only used in the corner case that the user launches an app using the launcher while in spread view. So not really critical performance wise. I can see why you dislike it, but as you said: not really a better idea around.
>
>
> + // FIXME: the signal connections seems to get lost.
> + // Check with Qt 5.2, see if we can remove this Connections and Binding
> objects
> 5.2 landed, fancy giving this a look?
Yep, checked. still an issue. I removed the "check with 5.2 phrase".
>
> + // PropertyAction seems to fail when secondApplicati
> have another screenshot before
> + ScriptAction { script: mainScreenshotI
> + spreadView.
> Weird, I don't see why a PropertyAction would be incorrect here. Did you try
> setting a binding instead of a value, just as an experiment?
Oh yeah... this one gave me quite a headache to figure why the heck it was failing. Tried the binding as you proposed too. Doesn't work. I've added a FIXME to the comment.
>
> + PropertyAction { target: fadeInScreensho
> ApplicationMana
> ApplicationMana
> pity you need to search twice here, could you not store the value temporarily?
done.
>
> + PropertyAction { target: fadeInScreensho
> false }
> + PropertyAction { target: mainScreenshotI
> false }
> Fun fact: can replace this with
> PropertyAction { targets: [fadeInScreensh
> property: "visible"; value: false }
> not a demand though, both ways are fine.
nice one. didn't know this. Love it!
>
> + UbuntuNumberAni
- 696. By Michael Zanetti
-
fix stuff from review
- 697. By Michael Zanetti
-
add some comments
- 698. By Michael Zanetti
-
rename stage to phase to avoid the obvious naming collision
- 699. By Michael Zanetti
-
add a break for future proveness
- 700. By Michael Zanetti
-
remove leftover
- 701. By Michael Zanetti
-
seems there's more leftover :D
Michael Zanetti (mzanetti) wrote : | # |
> Questions: there are 2 appSplash instances? Is that if user starts 2 apps
> quickly?
Yeah, it mostly catches the case that the screenshot is not available for some reason, for example the one you mentioned.
>
>
> + property bool attachedToView: true
> a comment explaining this would be nice. In fact, the logic in the
> EdgeDragArea could do with the same.
very valid. added.
>
> + if (oneWayFlick && spreadView.
> spreadView.
> please wrap that line a bit
wrapped all to 120 chars now.
>
> + property real positionMarker3: 0.6
> + property real positionMarker4: .9
> Consistency please
fixed.
>
> + // Stage of the animation:
> + property int stage: not a fan of the term, as "Stage" has a particular
> meaning for us. Would the Flickable's "States" system be useful here, as
> instead of numbers, can give the animation stages names?
Don't really want to go for strings as I do <, > comparison etc. While that would still work with strings its imo much more fail prone if someone renames or adds a stage. I did, however rename it to "phase" now to avoid the naming collision.
>
> + onShiftedConten
> + case 1:
> /me pedant, but adding "break" here too might spare a future coder some pain
fair enough, fixed.
>
> +// duration: UbuntuAnimation
> remove?
done.
>
> + spreadView.stage = 4;
> leftover?
seems so... dropped it.
>
> + if (spreadView.
> spreadView.
> what's going on here? floating point equality comparison makes me suspicious
Turns out its not needed any more at all as I later changed the logic to always hit the branch before in this case already.
>
> + id: spreadRow
> + width: Math.max(3, ApplicationMana
> (spreadView.width - spreadView.
> fancy maths could do with a comment explaining it :)
done.
> +++ qml/Stages/
> + anchors { left: parent.left; bottom: parent.bottom; top: parent.top;
> topMargin: priv.heightDiff
> please wrap so topMargin is on its own line, as that's the nontrivial bit.
done.
>
> + scale: 1
> unnecessary, that's the default value.
done
- 702. By Michael Zanetti
-
some more commenting
- 703. By Michael Zanetti
-
drop unnecessary line
- 704. By Michael Zanetti
-
fix tests
- 705. By Michael Zanetti
-
cleanup
Michael Zanetti (mzanetti) wrote : | # |
> +++ qml/Stages/
> + onApplicationCh
> application.
> debug info necessary?
>
> + signal switched()
> I prefer roughly sticking to the guidelines (http://
> /qml-coding-
> before javascript function definitions
>
> + Image {
> + visible: true
> should not be necessary
>
>
> You have a couple of commented out lines in this file too, please remove them.
all done. Sorry for that. Forgot to clean this one up before putting up for review.
Gerry Boland (gerboland) wrote : | # |
<greyback> old query of mine too: with spread open, long left edge swipe has launcher appear, then disappear, and nothing else happens
<greyback> that ok?
<mzanetti> ah right... so yes, the spread should not go away, that is wanted
<mzanetti> now the question is whether the launcher should hide again (as it does normally) or not
* greyback thinks it should stay open
<mzanetti> probably, yes
Gerry Boland (gerboland) wrote : | # |
<greyback> mind checking this: open 1 app, left swipe it away. Then tap it's entry in running apps. The slide in animation seems wrong
<mzanetti> mhm... true... wonder when that happened. will fix
- 706. By Michael Zanetti
-
more docs
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:695
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Michael Zanetti (mzanetti) wrote : | # |
> +++ qml/Stages/
>
> Since this relies heavily on the animation "stages" reported by the
> spreadView, a comment explaining the different behaviours of the tile in each
> stage (mentioning the position markers) would help a lot.
done
>
> + property real animatedProgress: 0
> purpose not obvious to me how it's different to "progress", add comment please
done.
>
> + property real tile1StartScale: startScale + .4
> + property real tile0SnapAngle: 10
> could be made readonly, or private actually.
actually intentional in public api as I hope to be able to reuse the TransformedAppD
>
> + priv.stage2star
> spreadView.
> + spreadView.width;
> confuses me, why the -spreadView.width offset for the animation?
tiles are attached to the right edge (outside) in the beginning and travel a distance of -spreadView.width during the progress of 0..1. So -spreadView.width is the end position. Should be more clear now that I added tons of comments all over the place.
>
> + // As they are static values, lets caluclate
> typo
fixed.
>
> + property real xTranslate: {
> in many of the calculations in this block, there's a "-spreadView.width" being
> used in the calculation of the start or end value in a linearAnimation. Could
> you add a note justifying it?
as explained above.
>
> + return linearAnimation
> selectedXTranslate, selectedXTranslate - spreadView.
> root.progress);
> please wrap
done
>
> + } else if(spreadView.stage == 1) {
> space needed after "if"
done
- 707. By Michael Zanetti
-
some more minor fixes
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:706
http://
Executed test runs:
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 : | # |
FAILED: Continuous integration, rev:707
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 708. By Michael Zanetti
-
drop some debug prints from mocked applicationmanager
- 709. By Michael Zanetti
-
only change app's status to running after some timeout
Michael Zanetti (mzanetti) wrote : | # |
> +++ tests/mocks/
> - ,m_state(Starting)
> + ,m_state(Running)
> looks wrong to me, why would an app start immediately in a "running" state.
> Real AppMan does not do that.
Ok. changed to start 'em up "Starting" and added a timer that switches them to "Running" after 300ms.
>
> +++ tests/mocks/
> +#include <QDebug>
> not needed
gone
>
> +++ tests/mocks/
> do we need the qDebugs?
gone
- 710. By Michael Zanetti
-
tiny cleanup as requested by review
- 711. By Michael Zanetti
-
update year in copyright header
Michael Zanetti (mzanetti) wrote : | # |
> +++ tests/mocks/
>
> + * Copyright (C) 2013 Canonical, Ltd.
> 2014
fixed.
>
> + if (app == NULL) {
> nullptr
fixed.
>
> + QGuiApplication *unity = qobject_
> can go inside the else block where it's actually used. Quick comment
> explaining what's going on would be handy too for the causal reader (you're
> scaling the image the the width of the window for all main stage apps).
fixed.
>
> qDebug needed?
removed most debugs. changed one to be a qWarning in case we can't find an image for the given app.
- 712. By Michael Zanetti
-
don't hide the launcher when the stages are locked and user does the long left edge swipe
Michael Zanetti (mzanetti) wrote : | # |
> <greyback> old query of mine too: with spread open, long left edge swipe has
> launcher appear, then disappear, and nothing else happens
> <greyback> that ok?
> <mzanetti> ah right... so yes, the spread should not go away, that is wanted
> <mzanetti> now the question is whether the launcher should hide again (as it
> does normally) or not
> * greyback thinks it should stay open
> <mzanetti> probably, yes
fixed. actually it even got me around the hide() vs forceHide() you disliked in an earlier comment
- 713. By Michael Zanetti
-
fix animation issue with focusing a running app when there's no focused app
- 714. By Michael Zanetti
-
get rid of src -> source mapping for mainScreenshotImage and with that the fixme for the PropertyAction not working
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:709
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Gerry Boland (gerboland) wrote : | # |
Tablet testing issues [MS=main stage, SS=side stage]
1) opening just 1 SS app, unable to swipe it away with SS handle
2) open some apps, then close them all, "Running apps" section of apps lens does not disappear like it used to
3) with 1 SS app open, unable to interact with Dash (missing InputFilterArea perhaps)
4) with only SS app open, open MS app (via launcher) - MS starting animation incorrect
5) with only SS app open, open MS app (via launcher) - SS dismissed
6) dismissed SS keeps a shadow on the right of the screen
7) 1 MS & 1 SS app open. Return to dash. Tap SS recent app - only SS app appears. Used to be that both MS & SS app appeared.
8) App lens - MS app preview much wider than it used to be, it used to be intentionally cropped
9) not sure why, but SS app preview image in the apps lens sometimes incorrect, sometimes stretched, sometimes offset wrong and being tiled inside the preview, and sometimes the wrong image entirely. Possibly a Nexus10 bug, just strange as the window animation screenshots seem to always look fine
10) 2 MS apps open: Clock & Browser, Browser focused. Return to dash and tap the Clock entry. The animation to bring Clock to the front isn't right, looks like mix of spread animation with usual slide in animation.
11) no right edge gesture at all now (for switching apps, think it was SS app switching)?
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:714
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Gerry Boland (gerboland) wrote : | # |
Phone functional testing pass 2 issues
1) Open 2 apps, return to dash. Tap preview on one app - the "bring to front" animation looks wrong
2) open 2 apps, go to spread. Open launcher and tap icon of focused app - nothing happens. Tapping icon of other app focuses it.
3)
>
> 12. With multiple apps open, bring up the OSK somehow. Then do right edge
> swipe to show spread. OSK stuck open
Yeah... that's a bit of an issue. Right now there's no way to hide the OSK except unfocing the app. ... Can we ignore this for this merge?
Ok, I can live with that.
- 715. By Michael Zanetti
-
add possibility to select an app from the spread from the outside.
- 716. By Michael Zanetti
-
add tests for the new select() function
Michael Zanetti (mzanetti) wrote : | # |
> <greyback> mind checking this: open 1 app, left swipe it away. Then tap
> it's entry in running apps. The slide in animation seems wrong
> <mzanetti> mhm... true... wonder when that happened. will fix
fixed.
> + Image {
> + id: mainScreenshotImage
> + property string src
> + source: src
> why not just use source everywhere?
along the way I got rid of this too, which also get away with this
+ // PropertyAction seems to fail when secondApplicati
Michael Zanetti (mzanetti) wrote : | # |
> Phone functional testing pass 2 issues
> 1) Open 2 apps, return to dash. Tap preview on one app - the "bring to front"
> animation looks wrong
fixed
> 2) open 2 apps, go to spread. Open launcher and tap icon of focused app -
> nothing happens. Tapping icon of other app focuses it.
> 3)
fixed.
- 717. By Michael Zanetti
-
drop ApplicationMana
gerWrapper & Co
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:715
http://
Executed test runs:
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 : | # |
FAILED: Continuous integration, rev:717
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 718. By Michael Zanetti
-
fix runningapplicat
ionsgrid tile width,
fix dash not intaractive when side stage overlaying
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:718
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 719. By Michael Zanetti
-
fix hiding of recent apps section when there's not app running
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:719
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 720. By Michael Zanetti
-
hide stage if no focused app is around any more
- 721. By Michael Zanetti
-
don't dismiss the SS if the user starts a MS app
- 722. By Michael Zanetti
-
hide the SS drag handle when SS is outside of the screen
Michael Zanetti (mzanetti) wrote : | # |
> Tablet testing issues [MS=main stage, SS=side stage]
> 1) opening just 1 SS app, unable to swipe it away with SS handle
fixed.
> 2) open some apps, then close them all, "Running apps" section of apps lens
> does not disappear like it used to
fixed.
> 3) with 1 SS app open, unable to interact with Dash (missing InputFilterArea
> perhaps)
fixed.
> 4) with only SS app open, open MS app (via launcher) - MS starting animation
> incorrect
Hmm... I did change something in this regard but not sure if this is h
> 5) with only SS app open, open MS app (via launcher) - SS dismissed
Uhm... ok. reverted the "fix" :)
> 6) dismissed SS keeps a shadow on the right of the screen
fixed.
> 7) 1 MS & 1 SS app open. Return to dash. Tap SS recent app - only SS app
> appears. Used to be that both MS & SS app appeared.
Yeah, but this time I really believe trunk's behavior is the wrong one :D
> 8) App lens - MS app preview much wider than it used to be, it used to be
> intentionally cropped
fixed.
> 9) not sure why, but SS app preview image in the apps lens sometimes
> incorrect, sometimes stretched, sometimes offset wrong and being tiled inside
> the preview, and sometimes the wrong image entirely. Possibly a Nexus10 bug,
> just strange as the window animation screenshots seem to always look fine
uhm... happens very rarely - I've seen it too today. Can we let this go and focus on eliminating the screenshots?
> 10) 2 MS apps open: Clock & Browser, Browser focused. Return to dash and tap
> the Clock entry. The animation to bring Clock to the front isn't right, looks
> like mix of spread animation with usual slide in animation.
Hmm.. not sure if I fixed this with other changed, but looks correct here.
> 11) no right edge gesture at all now (for switching apps, think it was SS app
> switching)?
I hoped to get a bypass ticket on that one instead of juggling screenshots around just to remove them with my next task again. But if it turns out this is too much breakage, I'll obviously do my best to fix this too.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:720
http://
Executed test runs:
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 : | # |
FAILED: Continuous integration, rev:722
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 723. By Michael Zanetti
-
added a test to check for correct fullscreen behavior
- 724. By Michael Zanetti
-
improve test a bit
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:724
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 725. By Michael Zanetti
-
add splash screen to tablet stuff
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:725
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Gerry Boland (gerboland) wrote : | # |
Running AP tests, here are my results: http://
Unity8 fails some tests
- 726. By Michael Zanetti
-
some improvements in the sidestage
- 727. By Michael Zanetti
-
bring back workaround for unlocking the greeter when an app is started "somehow"
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:726
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 728. By Michael Zanetti
-
increase splash timer a little, add todo
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:727
http://
Executed test runs:
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 : | # |
FAILED: Continuous integration, rev:728
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 729. By Michael Zanetti
-
make AP work again
- 730. By Michael Zanetti
-
fix newline at EOF
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:729
http://
Executed test runs:
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 : | # |
FAILED: Continuous integration, rev:730
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Albert Astals Cid (aacid) wrote : | # |
Needs merging with trunk
Text conflict in qml/Dash/
Contents conflict in qml/Dash/
Text conflict in qml/Dash/
Text conflict in qml/Shell.qml
Text conflict in tests/autopilot
- 731. By Michael Zanetti
-
bump required unity-api version
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:731
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 732. By Michael Zanetti
-
merge trunk
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:732
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 733. By Michael Zanetti
-
bring back the paper background that accidentally got dropped in the last merge
- 734. By Michael Zanetti
-
fix autopilot tests after merge
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:733
http://
Executed test runs:
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 : | # |
FAILED: Continuous integration, rev:734
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 735. By Michael Zanetti
-
make it a bit better, still broken tho :/
- 736. By Michael Zanetti
-
more improvements, still not working
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:735
http://
Executed test runs:
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 : | # |
FAILED: Continuous integration, rev:736
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Mirco Müller (macslow) wrote : | # |
I ran ppa:ci-
http://
http://
http://
http://
Before that I had up to ten applications running (among them camera-app and browser) and there was no single glitch. I'm still trying to find a way to trigger this bug in a reproducable manner.
Mirco Müller (macslow) wrote : | # |
Here's a screencast better showing off the "invisible" apps and the empty app-previews: https:/
Michael Zanetti (mzanetti) wrote : | # |
> I ran ppa:ci-
> https:/
> good. Especially the new right-edge feels robust and slick. But I came across
> this issue with starting the Notes app...
>
> http://
> http://
> http://
> http://
>
> Before that I had up to ten applications running (among them camera-app and
> browser) and there was no single glitch. I'm still trying to find a way to
> trigger this bug in a reproducable manner.
The misplaced surface is fixed in another branch in unity-mir. I've added it to the silo. Upgrading it should get it fixed. The missing image however, happens if an app fails to start. Its the same behavior as current trunk.
Michael Zanetti (mzanetti) wrote : | # |
> The missing image however,
> happens if an app fails to start. Its the same behavior as current trunk.
Some more details: This is in unity-mir and possibly even lower layers. The situation will improve once we have the live surfaces (it will fix the case where the screenshot is missing if you swipe it away before its loaded), and for apps not starting at all, we need to figure a solution in ApplicationManager. I don't adding a workaround in here is the way to go.
Mirco Müller (macslow) wrote : | # |
After the second run through the test-plan with the reconfigure-fixes in the PPA, I'm ok with the results. All works nicely. Good to go.
Gerry Boland (gerboland) wrote : | # |
Code-wise I'm happy to go too. I did a quick test of phone and it was good too. Not done a last tablet check however
Gerry Boland (gerboland) wrote : | # |
* Did you perform an exploratory manual test run of the code change and any related functionality?
Hell yeah
* Did CI run pass? If not, please explain why.
Dependant branches, listed in description
Unmerged revisions
Preview Diff
1 | === modified file 'debian/control' |
2 | --- debian/control 2014-03-24 11:49:06 +0000 |
3 | +++ debian/control 2014-03-25 15:08:15 +0000 |
4 | @@ -17,7 +17,7 @@ |
5 | libnih-dev, |
6 | libpulse-dev, |
7 | libqmenumodel-dev (>= 0.2.7), |
8 | - libunity-api-dev (>= 7.80.4), |
9 | + libunity-api-dev (>= 7.80.6), |
10 | libunity-mir-dev, |
11 | libupstart-dev, |
12 | libusermetricsoutput1-dev, |
13 | @@ -83,6 +83,7 @@ |
14 | qtdeclarative5-ubuntu-ui-toolkit-plugin, |
15 | qtdeclarative5-unity-notifications-plugin | unity-notifications-impl, |
16 | qtdeclarative5-xmllistmodel-plugin, |
17 | + unity-application-impl-2, |
18 | unity-launcher-impl-3, |
19 | unity-notifications-impl-2, |
20 | unity8-fake-env | qtubuntu-shell, |
21 | @@ -147,6 +148,7 @@ |
22 | ${shlibs:Depends}, |
23 | Provides: unity-launcher-impl, |
24 | unity-launcher-impl-3, |
25 | + unity-application-impl-2, |
26 | Description: Unity 8 private libs |
27 | The Unity 8 shell is the primary user interface for Ubuntu devices. |
28 | . |
29 | |
30 | === modified file 'debian/unity8.install' |
31 | --- debian/unity8.install 2014-03-05 12:52:57 +0000 |
32 | +++ debian/unity8.install 2014-03-25 15:08:15 +0000 |
33 | @@ -10,6 +10,6 @@ |
34 | usr/share/unity8/Notifications |
35 | usr/share/unity8/Panel |
36 | usr/share/unity8/Shell.qml |
37 | -usr/share/unity8/SideStage |
38 | +usr/share/unity8/Stages |
39 | usr/share/unity8/graphics |
40 | data/unity8.conf usr/share/upstart/sessions/ |
41 | |
42 | === modified file 'plugins/Utils/CMakeLists.txt' |
43 | --- plugins/Utils/CMakeLists.txt 2014-03-17 15:50:50 +0000 |
44 | +++ plugins/Utils/CMakeLists.txt 2014-03-25 15:08:15 +0000 |
45 | @@ -18,6 +18,7 @@ |
46 | qsortfilterproxymodelqml.cpp |
47 | timeformatter.cpp |
48 | unitymenumodelpaths.cpp |
49 | + easingcurve.cpp |
50 | plugin.cpp |
51 | ) |
52 | |
53 | @@ -33,7 +34,7 @@ |
54 | # files directly in targets. |
55 | set_target_properties(Utils-qml PROPERTIES COMPILE_FLAGS -fvisibility=default) |
56 | |
57 | -qt5_use_modules(Utils-qml Qml Quick DBus Network XmlPatterns Concurrent) |
58 | +qt5_use_modules(Utils-qml Qml Quick DBus Network XmlPatterns Gui Concurrent) |
59 | |
60 | # export the qmldir qmltypes and plugin files |
61 | export_qmlfiles(Utils Utils) |
62 | |
63 | === added file 'plugins/Utils/easingcurve.cpp' |
64 | --- plugins/Utils/easingcurve.cpp 1970-01-01 00:00:00 +0000 |
65 | +++ plugins/Utils/easingcurve.cpp 2014-03-25 15:08:15 +0000 |
66 | @@ -0,0 +1,67 @@ |
67 | +/* |
68 | + * Copyright 2014 Canonical Ltd. |
69 | + * |
70 | + * This program is free software; you can redistribute it and/or modify |
71 | + * it under the terms of the GNU Lesser General Public License as published by |
72 | + * the Free Software Foundation; version 3. |
73 | + * |
74 | + * This program is distributed in the hope that it will be useful, |
75 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
76 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
77 | + * GNU Lesser General Public License for more details. |
78 | + * |
79 | + * You should have received a copy of the GNU Lesser General Public License |
80 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
81 | + * |
82 | + * Authors: Michael Zanetti <michael.zanetti@canonical.com> |
83 | +*/ |
84 | + |
85 | +#include "easingcurve.h" |
86 | + |
87 | + |
88 | +EasingCurve::EasingCurve(QObject *parent): |
89 | + QObject(parent) |
90 | +{ |
91 | + |
92 | +} |
93 | + |
94 | +QEasingCurve::Type EasingCurve::type() const |
95 | +{ |
96 | + return m_easingCurve.type(); |
97 | +} |
98 | + |
99 | +void EasingCurve::setType(const QEasingCurve::Type &type) |
100 | +{ |
101 | + m_easingCurve.setType(type); |
102 | + Q_EMIT typeChanged(); |
103 | +} |
104 | + |
105 | +qreal EasingCurve::period() const |
106 | +{ |
107 | + return m_easingCurve.period(); |
108 | +} |
109 | + |
110 | +void EasingCurve::setPeriod(qreal period) |
111 | +{ |
112 | + m_easingCurve.setPeriod(period); |
113 | + Q_EMIT periodChanged(); |
114 | +} |
115 | + |
116 | +qreal EasingCurve::progress() const |
117 | +{ |
118 | + return m_progress; |
119 | +} |
120 | + |
121 | +void EasingCurve::setProgress(qreal progress) |
122 | +{ |
123 | + if (m_progress != progress) { |
124 | + m_progress = progress; |
125 | + m_value = m_easingCurve.valueForProgress(m_progress); |
126 | + Q_EMIT progressChanged(); |
127 | + } |
128 | +} |
129 | + |
130 | +qreal EasingCurve::value() const |
131 | +{ |
132 | + return m_value; |
133 | +} |
134 | |
135 | === added file 'plugins/Utils/easingcurve.h' |
136 | --- plugins/Utils/easingcurve.h 1970-01-01 00:00:00 +0000 |
137 | +++ plugins/Utils/easingcurve.h 2014-03-25 15:08:15 +0000 |
138 | @@ -0,0 +1,70 @@ |
139 | +/* |
140 | + * Copyright 2014 Canonical Ltd. |
141 | + * |
142 | + * This program is free software; you can redistribute it and/or modify |
143 | + * it under the terms of the GNU Lesser General Public License as published by |
144 | + * the Free Software Foundation; version 3. |
145 | + * |
146 | + * This program is distributed in the hope that it will be useful, |
147 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
148 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
149 | + * GNU Lesser General Public License for more details. |
150 | + * |
151 | + * You should have received a copy of the GNU Lesser General Public License |
152 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
153 | + * |
154 | + * Authors: Michael Zanetti <michael.zanetti@canonical.com> |
155 | +*/ |
156 | + |
157 | +#ifndef EASINGCURVE_H |
158 | +#define EASINGCURVE_H |
159 | + |
160 | +#include <QObject> |
161 | +#include <QEasingCurve> |
162 | + |
163 | +/** |
164 | + * @brief The EasingCurve class |
165 | + * |
166 | + * This class exposes the QEasingCurve C++ API to QML. |
167 | + * This is useful for user interactive animations. While the QML Animation types |
168 | + * all require a "from", "to" and "duration", this one is based on "period" and |
169 | + * "progress". So you can control the position of the aimation by changing the |
170 | + * progress, also going back and forward in the animation. Depending on the type |
171 | + * of the easing curve, value will return the transformed progress. |
172 | + */ |
173 | + |
174 | +class EasingCurve: public QObject |
175 | +{ |
176 | + Q_OBJECT |
177 | + Q_ENUMS(QEasingCurve::Type) |
178 | + Q_PROPERTY(QEasingCurve::Type type READ type WRITE setType NOTIFY typeChanged) |
179 | + Q_PROPERTY(qreal period READ period WRITE setPeriod NOTIFY periodChanged) |
180 | + Q_PROPERTY(qreal progress READ progress WRITE setProgress NOTIFY progressChanged) |
181 | + Q_PROPERTY(qreal value READ value NOTIFY progressChanged) |
182 | + |
183 | +public: |
184 | + EasingCurve(QObject *parent = 0); |
185 | + |
186 | + QEasingCurve::Type type() const; |
187 | + void setType(const QEasingCurve::Type &type); |
188 | + |
189 | + qreal period() const; |
190 | + void setPeriod(qreal period); |
191 | + |
192 | + qreal progress() const; |
193 | + void setProgress(qreal progress); |
194 | + |
195 | + qreal value() const; |
196 | + |
197 | +Q_SIGNALS: |
198 | + void typeChanged(); |
199 | + void periodChanged(); |
200 | + void progressChanged(); |
201 | + |
202 | +private: |
203 | + QEasingCurve m_easingCurve; |
204 | + qreal m_progress; |
205 | + qreal m_value; |
206 | +}; |
207 | + |
208 | +#endif |
209 | |
210 | === modified file 'plugins/Utils/plugin.cpp' |
211 | --- plugins/Utils/plugin.cpp 2014-03-17 15:50:50 +0000 |
212 | +++ plugins/Utils/plugin.cpp 2014-03-25 15:08:15 +0000 |
213 | @@ -32,6 +32,7 @@ |
214 | #include "qsortfilterproxymodelqml.h" |
215 | #include "timeformatter.h" |
216 | #include "unitymenumodelpaths.h" |
217 | +#include "easingcurve.h" |
218 | |
219 | static const char* BOTTOM_BAR_VISIBILITY_COMMUNICATOR_DBUS_PATH = "/BottomBarVisibilityCommunicator"; |
220 | static const char* DBUS_SERVICE = "com.canonical.Shell.BottomBarVisibilityCommunicator"; |
221 | @@ -46,6 +47,7 @@ |
222 | qmlRegisterType<TimeFormatter>(uri, 0, 1, "TimeFormatter"); |
223 | qmlRegisterType<GDateTimeFormatter>(uri, 0, 1, "GDateTimeFormatter"); |
224 | qmlRegisterUncreatableType<BottomBarVisibilityCommunicatorShell>(uri, 0, 1, "BottomBarVisibilityCommunicatorShell", "Can't create BottomBarVisibilityCommunicatorShell"); |
225 | + qmlRegisterType<EasingCurve>(uri, 0, 1, "EasingCurve"); |
226 | } |
227 | |
228 | void UtilsPlugin::initializeEngine(QQmlEngine *engine, const char *uri) |
229 | |
230 | === modified file 'qml/CMakeLists.txt' |
231 | --- qml/CMakeLists.txt 2013-12-17 16:04:47 +0000 |
232 | +++ qml/CMakeLists.txt 2014-03-25 15:08:15 +0000 |
233 | @@ -13,7 +13,7 @@ |
234 | Hud |
235 | Panel |
236 | Launcher |
237 | - SideStage |
238 | + Stages |
239 | Notifications |
240 | ) |
241 | |
242 | |
243 | === removed file 'qml/Components/ApplicationManagerWrapper.qml' |
244 | --- qml/Components/ApplicationManagerWrapper.qml 2014-03-05 12:52:57 +0000 |
245 | +++ qml/Components/ApplicationManagerWrapper.qml 1970-01-01 00:00:00 +0000 |
246 | @@ -1,169 +0,0 @@ |
247 | -/* |
248 | - * Copyright (C) 2013 Canonical, Ltd. |
249 | - * |
250 | - * This program is free software; you can redistribute it and/or modify |
251 | - * it under the terms of the GNU General Public License as published by |
252 | - * the Free Software Foundation; version 3. |
253 | - * |
254 | - * This program is distributed in the hope that it will be useful, |
255 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
256 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
257 | - * GNU General Public License for more details. |
258 | - * |
259 | - * You should have received a copy of the GNU General Public License |
260 | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
261 | - */ |
262 | - |
263 | -import QtQuick 2.0 |
264 | -import Unity.Application 0.1 |
265 | - |
266 | -Item { |
267 | - id: root |
268 | - |
269 | - property alias mainStageApplications: mainStageModel |
270 | - property alias sideStageApplications: sideStageModel |
271 | - property variant mainStageFocusedApplication: null |
272 | - property variant sideStageFocusedApplication: null |
273 | - property bool sideStageEnabled: true |
274 | - property bool keyboardVisible: ApplicationManager.keyboardVisible |
275 | - property int keyboardHeight: ApplicationManager.keyboardHeight |
276 | - |
277 | - property bool fake: ApplicationManager.fake ? ApplicationManager.fake : false |
278 | - |
279 | - signal focusRequested(string appId) |
280 | - |
281 | - ApplicationsModelStageFiltered { |
282 | - id: mainStageModel |
283 | - stage: ApplicationInfo.MainStage |
284 | - } |
285 | - |
286 | - ApplicationsModelStageFiltered { |
287 | - id: sideStageModel |
288 | - stage: ApplicationInfo.SideStage |
289 | - } |
290 | - |
291 | - Connections { |
292 | - target: ApplicationManager |
293 | - onFocusedApplicationIdChanged: { |
294 | - var app = ApplicationManager.findApplication(ApplicationManager.focusedApplicationId) |
295 | - if (!app) { //nothing at all focused, so clear all |
296 | - mainStageFocusedApplication = null; |
297 | - sideStageFocusedApplication = null; |
298 | - } else { |
299 | - if (app.stage == ApplicationInfo.MainStage) { |
300 | - mainStageFocusedApplication = app; |
301 | - // possible the side stage app being unfocused fired this signal, so check for it |
302 | - if (sideStageFocusedApplication && !sideStageFocusedApplication.focused) |
303 | - sideStageFocusedApplication = null; |
304 | - } else { |
305 | - sideStageFocusedApplication = app; |
306 | - // possible the main stage app being unfocused fired this signal, so check for it |
307 | - if (mainStageFocusedApplication && !mainStageFocusedApplication.focused) |
308 | - mainStageFocusedApplication = null; |
309 | - } |
310 | - } |
311 | - } |
312 | - |
313 | - onFocusRequested: { |
314 | - // if no side stage enabled, override application's stage parameter |
315 | - var app = ApplicationManager.findApplication(appId); |
316 | - if (app && app.stage === ApplicationInfo.SideStage && !sideStageEnabled) { |
317 | - app.stage = ApplicationInfo.MainStage; |
318 | - } |
319 | - |
320 | - root.focusRequested(appId); |
321 | - } |
322 | - } |
323 | - |
324 | - function activateApplication(desktopFile, argument) { |
325 | - var appId; |
326 | - |
327 | - // HACK: Applications identified sometimes with with appId, but mostly with desktopFile. |
328 | - // TODO: convert entire shell to use appId only. |
329 | - if (desktopFile.indexOf(".desktop") >= 0) { |
330 | - appId = desktopFileToAppId(desktopFile); |
331 | - } else { |
332 | - appId = desktopFile; |
333 | - } |
334 | - |
335 | - var application = ApplicationManager.findApplication(appId); |
336 | - if (application !== null) { |
337 | - return application; |
338 | - } |
339 | - |
340 | - var execFlags = sideStageEnabled ? ApplicationManager.NoFlag : ApplicationManager.ForceMainStage; |
341 | - |
342 | - if (argument) { |
343 | - return ApplicationManager.startApplication(appId, execFlags, [argument]); |
344 | - } else { |
345 | - return ApplicationManager.startApplication(appId, execFlags); |
346 | - } |
347 | - } |
348 | - |
349 | - function stopApplication(application) { |
350 | - var appId; |
351 | - |
352 | - // HACK: Applications identified sometimes with with appId, but mostly with desktopFile. |
353 | - // TODO: convert entire shell to use appId only. |
354 | - if (typeof application == "string") { |
355 | - appId = application; |
356 | - } else { |
357 | - appId = desktopFileToAppId(application.desktopFile); |
358 | - } |
359 | - |
360 | - ApplicationManager.stopApplication(appId); |
361 | - } |
362 | - |
363 | - function focusApplication(application) { |
364 | - if (application == null || application == undefined) { |
365 | - return; |
366 | - } |
367 | - |
368 | - ApplicationManager.focusApplication(application.appId); |
369 | - } |
370 | - |
371 | - function unfocusCurrentApplication() { |
372 | - ApplicationManager.unfocusCurrentApplication(); |
373 | - } |
374 | - |
375 | - function moveRunningApplicationStackPosition(from, to, stage) { |
376 | - if (from == to || from < 0 || to < 0) return; |
377 | - |
378 | - if (stage == ApplicationInfo.SideStage) { |
379 | - sideStageModel.move(from, to); |
380 | - } else { |
381 | - mainStageModel.move(from, to); |
382 | - } |
383 | - } |
384 | - |
385 | - function getApplicationFromDesktopFile(desktopFile, stage) { |
386 | - var appId; |
387 | - |
388 | - // HACK: Applications identified sometimes with with appId, but mostly with desktopFile. |
389 | - // TODO: convert entire shell to use appId only. |
390 | - if (desktopFile.indexOf(".desktop") >= 0) { |
391 | - appId = desktopFileToAppId(desktopFile); |
392 | - } else { |
393 | - appId = desktopFile; |
394 | - } |
395 | - |
396 | - for (var i = 0, len = ApplicationManager.count; i < len; i++ ) { |
397 | - var app = ApplicationManager.get(i); |
398 | - |
399 | - // if stage not specified, return whichever app running on either stage |
400 | - if (app.appId == appId && (stage == undefined || app.stage == stage)) { |
401 | - return app; |
402 | - } |
403 | - } |
404 | - } |
405 | - |
406 | - function desktopFileToAppId(desktopFile) { |
407 | - var right = desktopFile.lastIndexOf(".desktop"); |
408 | - var left = desktopFile.lastIndexOf("/"); |
409 | - if (left == -1 || right == -1 || left == right) { |
410 | - console.log("ApplicationManagerWrapper: unable to extract appId from '" + desktopFile + "'"); |
411 | - return ""; |
412 | - } |
413 | - return desktopFile.substring(left+1, right); |
414 | - } |
415 | -} |
416 | |
417 | === removed file 'qml/Components/ApplicationScreenshot.qml' |
418 | --- qml/Components/ApplicationScreenshot.qml 2014-03-05 12:52:57 +0000 |
419 | +++ qml/Components/ApplicationScreenshot.qml 1970-01-01 00:00:00 +0000 |
420 | @@ -1,61 +0,0 @@ |
421 | -/* |
422 | - * Copyright (C) 2013 Canonical, Ltd. |
423 | - * |
424 | - * This program is free software; you can redistribute it and/or modify |
425 | - * it under the terms of the GNU General Public License as published by |
426 | - * the Free Software Foundation; version 3. |
427 | - * |
428 | - * This program is distributed in the hope that it will be useful, |
429 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
430 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
431 | - * GNU General Public License for more details. |
432 | - * |
433 | - * You should have received a copy of the GNU General Public License |
434 | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
435 | - */ |
436 | - |
437 | -import QtQuick 2.0 |
438 | -import Ubuntu.Components 0.1 |
439 | -import Unity.Application 0.1 |
440 | - |
441 | -Item { |
442 | - id: applicationScreenshot |
443 | - |
444 | - property var application: null |
445 | - property bool withBackground: false |
446 | - property bool ready: applicationImage.ready || withBackground |
447 | - |
448 | - function setApplication(application) { |
449 | - applicationScreenshot.application = application |
450 | - } |
451 | - |
452 | - function clearApplication() { |
453 | - applicationScreenshot.withBackground = false; |
454 | - applicationScreenshot.application = null |
455 | - applicationScreenshot.scheduleUpdate(); |
456 | - } |
457 | - |
458 | - function scheduleUpdate() { |
459 | - applicationImage.scheduleUpdate() |
460 | - } |
461 | - |
462 | - function updateFromCache() { |
463 | - applicationImage.updateFromCache() |
464 | - } |
465 | - |
466 | - Rectangle { |
467 | - id: background |
468 | - anchors.fill: parent |
469 | - color: "white" // FIXME should use normal background color of Suru theme |
470 | - visible: applicationScreenshot.withBackground |
471 | - } |
472 | - |
473 | - ApplicationImage { |
474 | - id: applicationImage |
475 | - objectName: "screenshot image" |
476 | - width: applicationScreenshot.application ? parent.width : 0 |
477 | - height: applicationScreenshot.application ? parent.height : 0 |
478 | - visible: applicationScreenshot.application != null && ready |
479 | - source: ApplicationManager.findApplication((application) ? application.appId : "") |
480 | - } |
481 | -} |
482 | |
483 | === removed file 'qml/Components/ApplicationsModelStageFiltered.qml' |
484 | --- qml/Components/ApplicationsModelStageFiltered.qml 2013-09-09 10:20:21 +0000 |
485 | +++ qml/Components/ApplicationsModelStageFiltered.qml 1970-01-01 00:00:00 +0000 |
486 | @@ -1,49 +0,0 @@ |
487 | -/* |
488 | - * Copyright (C) 2013 Canonical, Ltd. |
489 | - * |
490 | - * This program is free software; you can redistribute it and/or modify |
491 | - * it under the terms of the GNU General Public License as published by |
492 | - * the Free Software Foundation; version 3. |
493 | - * |
494 | - * This program is distributed in the hope that it will be useful, |
495 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
496 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
497 | - * GNU General Public License for more details. |
498 | - * |
499 | - * You should have received a copy of the GNU General Public License |
500 | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
501 | - */ |
502 | - |
503 | -import QtQuick 2.0 |
504 | -import Utils 0.1 |
505 | -import Unity.Application 0.1 |
506 | - |
507 | -SortFilterProxyModel { |
508 | - id: root |
509 | - property int stage |
510 | - |
511 | - function get(index) { |
512 | - return model.get(mapRowToSource(index)); |
513 | - } |
514 | - |
515 | - function move(from, to) { |
516 | - var realFrom = mapRowToSource(from); |
517 | - if (realFrom == -1) { |
518 | - console.log("ERROR; invalid from=" + from + " index in move operation"); |
519 | - return; |
520 | - } |
521 | - var realTo = mapRowToSource(to); |
522 | - if (realTo == -1) { |
523 | - // assuming wanting to move to end of list |
524 | - realTo = model.count - 1; |
525 | - } |
526 | - |
527 | - if (realFrom == realTo) return; |
528 | - model.move(realFrom, realTo); |
529 | - } |
530 | - |
531 | - model: ApplicationManager |
532 | - dynamicSortFilter: true |
533 | - filterRole: ApplicationManager.RoleStage |
534 | - filterRegExp: RegExp(stage) |
535 | -} |
536 | |
537 | === modified file 'qml/Components/ResponsiveFlowView.qml' |
538 | --- qml/Components/ResponsiveFlowView.qml 2013-06-05 22:03:08 +0000 |
539 | +++ qml/Components/ResponsiveFlowView.qml 2014-03-25 15:08:15 +0000 |
540 | @@ -27,9 +27,8 @@ |
541 | property alias verticalSpacing: flow.verticalSpacing |
542 | property alias horizontalSpacing: flow.horizontalSpacing |
543 | property int referenceDelegateWidth |
544 | - property alias firstModel: repeater1.model |
545 | - property alias secondModel: repeater2.model |
546 | - property alias delegate: repeater1.delegate |
547 | + property alias model: repeater.model |
548 | + property alias delegate: repeater.delegate |
549 | readonly property int cellWidth: referenceDelegateWidth + horizontalSpacing |
550 | readonly property int cellHeight: referenceDelegateWidth + verticalSpacing |
551 | property alias move: flow.move |
552 | @@ -69,13 +68,7 @@ |
553 | property int margin: allocatableVerticalSpace - columns * horizontalSpacing |
554 | |
555 | Repeater { |
556 | - id: repeater1 |
557 | - model: (root.model) ? root.model[0] : null |
558 | - } |
559 | - Repeater { |
560 | - id: repeater2 |
561 | - model: (root.model) ? root.model[1] : null |
562 | - delegate: repeater1.delegate |
563 | + id: repeater |
564 | } |
565 | } |
566 | } |
567 | |
568 | === modified file 'qml/Dash/Apps/RunningApplicationTile.qml' |
569 | --- qml/Dash/Apps/RunningApplicationTile.qml 2014-03-12 10:44:18 +0000 |
570 | +++ qml/Dash/Apps/RunningApplicationTile.qml 2014-03-25 15:08:15 +0000 |
571 | @@ -23,7 +23,6 @@ |
572 | AbstractButton { |
573 | id: root |
574 | property var application |
575 | - property bool __sideStageEnabled: shell.applicationManager.sideStageEnabled |
576 | |
577 | signal requestedApplicationActivation(var application) |
578 | signal requestedApplicationTermination(var application) |
579 | @@ -34,7 +33,7 @@ |
580 | // To avoid "binding loop" warning |
581 | height: shapedApplicationImage.height + labelContainer.height |
582 | |
583 | - width: shapedApplicationImage.width |
584 | + width: shapedApplicationImage.width <= units.gu(11) ? units.gu(11) : height |
585 | |
586 | property bool terminationModeEnabled: false |
587 | |
588 | @@ -51,32 +50,23 @@ |
589 | } |
590 | } |
591 | |
592 | - function updateScreenshotFromCache() { |
593 | - applicationImage.updateFromCache(); |
594 | - } |
595 | - |
596 | - // FIXME: should use UbuntuShape from SDK |
597 | - UbuntuShapeForItem { |
598 | + UbuntuShape { |
599 | id: shapedApplicationImage |
600 | - anchors { |
601 | - top: parent.top |
602 | - horizontalCenter: parent.horizontalCenter |
603 | + anchors { top: parent.top; horizontalCenter: parent.horizontalCenter } |
604 | + |
605 | + height: units.gu(17) |
606 | + width: applicationImage.width |
607 | + radius: "medium" |
608 | + |
609 | + image: Image { |
610 | + id: applicationImage |
611 | + source: application.screenshot |
612 | + // height : width = ss.height : ss.width |
613 | + height: shapedApplicationImage.height |
614 | + fillMode: Image.PreserveAspectCrop |
615 | + width: Math.min(height, height * sourceSize.width / sourceSize.height) |
616 | } |
617 | |
618 | - // FIXME: width and height should be defined according to the |
619 | - // application window's aspect ratio. |
620 | - width: (application.stage === ApplicationInfo.MainStage && __sideStageEnabled) ? |
621 | - units.gu(22) : units.gu(11) |
622 | - height: (__sideStageEnabled) ? units.gu(22) : units.gu(19) |
623 | - radius: "medium" |
624 | - image: applicationImage |
625 | - } |
626 | - |
627 | - ApplicationImage { |
628 | - id: applicationImage |
629 | - source: ApplicationManager.findApplication((application) ? application.appId : "") |
630 | - width: shapedApplicationImage.width |
631 | - height: shapedApplicationImage.height |
632 | } |
633 | |
634 | UbuntuShape { |
635 | |
636 | === modified file 'qml/Dash/Apps/RunningApplicationsGrid.qml' |
637 | --- qml/Dash/Apps/RunningApplicationsGrid.qml 2014-02-26 11:04:54 +0000 |
638 | +++ qml/Dash/Apps/RunningApplicationsGrid.qml 2014-03-25 15:08:15 +0000 |
639 | @@ -18,6 +18,7 @@ |
640 | import "../../Components" |
641 | |
642 | import Ubuntu.Gestures 0.1 |
643 | +import Unity.Application 0.1 |
644 | |
645 | ResponsiveFlowView { |
646 | id: root |
647 | @@ -25,13 +26,7 @@ |
648 | |
649 | signal updateScreenshots |
650 | property alias enableHeightBehavior: heightBehaviour.enabled |
651 | - property bool enableHeightBehaviorOnNextCreation: firstModel.count + secondModel.count == 0 |
652 | - |
653 | - Connections { |
654 | - target: shell |
655 | - onDashShownChanged: if (shell.dashShown && shell.stageScreenshotsReady) updateScreenshots(); |
656 | - onStageScreenshotsReadyChanged: if (shell.dashShown && shell.stageScreenshotsReady) updateScreenshots(); |
657 | - } |
658 | + property bool enableHeightBehaviorOnNextCreation: model.count === 0 |
659 | |
660 | Behavior on height { |
661 | id: heightBehaviour |
662 | @@ -40,13 +35,7 @@ |
663 | } |
664 | |
665 | Connections { |
666 | - target: root.firstModel |
667 | - onCountChanged: { |
668 | - heightBehaviour.enabled = true; |
669 | - } |
670 | - } |
671 | - Connections { |
672 | - target: root.secondModel |
673 | + target: root.model |
674 | onCountChanged: { |
675 | heightBehaviour.enabled = true; |
676 | } |
677 | @@ -85,17 +74,13 @@ |
678 | root.terminationModeEnabled = true |
679 | } |
680 | onRequestedApplicationTermination: { |
681 | - shell.applicationManager.stopApplication(model.appId) |
682 | + ApplicationManager.stopApplication(model.appId) |
683 | } |
684 | onRequestedApplicationActivation: { |
685 | - shell.activateApplication(model.appId) |
686 | + ApplicationManager.requestFocusApplication(model.appId) |
687 | } |
688 | |
689 | terminationModeEnabled: root.terminationModeEnabled |
690 | - |
691 | - Component.onCompleted: { |
692 | - root.updateScreenshots.connect(updateScreenshotFromCache); |
693 | - } |
694 | } |
695 | } |
696 | |
697 | |
698 | === modified file 'qml/Dash/DashApps.qml' |
699 | --- qml/Dash/DashApps.qml 2014-02-19 11:15:01 +0000 |
700 | +++ qml/Dash/DashApps.qml 2014-03-25 15:08:15 +0000 |
701 | @@ -17,6 +17,7 @@ |
702 | import QtQuick 2.0 |
703 | import Ubuntu.Components 0.1 |
704 | import Utils 0.1 |
705 | +import Unity.Application 0.1 |
706 | import "../Components" |
707 | import "../Components/ListItems" |
708 | import "Apps" |
709 | @@ -25,17 +26,15 @@ |
710 | id: scopeView |
711 | objectName: "DashApps" |
712 | |
713 | - // FIXME: a way to aggregate these models would be ideal |
714 | - property var mainStageApplicationsModel: shell.applicationManager.mainStageApplications |
715 | - property var sideStageApplicationModel: shell.applicationManager.sideStageApplications |
716 | + property var runningApps: ApplicationManager |
717 | |
718 | QtObject { |
719 | id: countObject |
720 | - property int count: scopeView.scope.searchQuery.length == 0 ? (mainStageApplicationsModel.count + sideStageApplicationModel.count) : 0 |
721 | + property int count: scopeView.scope.searchQuery.length == 0 ? scopeView.runningApps.count : 0 |
722 | } |
723 | |
724 | onScopeChanged: { |
725 | scopeView.scope.categories.addSpecialCategory("running.apps.category", "Recent", "", "{ \"template\": { \"category-layout\": \"running-apps\" } }", countObject); |
726 | - enableHeightBehaviorOnNextCreation = (mainStageApplicationsModel.count + sideStageApplicationModel.count == 0) |
727 | + enableHeightBehaviorOnNextCreation = scopeView.runningApps.count === 0 |
728 | } |
729 | } |
730 | |
731 | === modified file 'qml/Dash/GenericScopeView.qml' |
732 | --- qml/Dash/GenericScopeView.qml 2014-03-17 11:44:05 +0000 |
733 | +++ qml/Dash/GenericScopeView.qml 2014-03-25 15:08:15 +0000 |
734 | @@ -18,6 +18,7 @@ |
735 | import Ubuntu.Components 0.1 |
736 | import Utils 0.1 |
737 | import Unity 0.2 |
738 | +import Unity.Application 0.1 |
739 | import "../Components" |
740 | import "../Components/ListItems" as ListItems |
741 | |
742 | @@ -167,8 +168,7 @@ |
743 | if (source.toString().indexOf("Apps/RunningApplicationsGrid.qml") != -1) { |
744 | // TODO: this is still a kludge :D Ideally add some kind of hook so that we |
745 | // can do this from DashApps.qml or think a better way that needs no special casing |
746 | - item.firstModel = Qt.binding(function() { return mainStageApplicationsModel }) |
747 | - item.secondModel = Qt.binding(function() { return sideStageApplicationModel }) |
748 | + item.model = Qt.binding(function() { return runningApps; }) |
749 | item.canEnableTerminationMode = Qt.binding(function() { return scopeView.isCurrent }) |
750 | } else { |
751 | item.model = Qt.binding(function() { return results }) |
752 | |
753 | === modified file 'qml/Launcher/Launcher.qml' |
754 | --- qml/Launcher/Launcher.qml 2013-12-11 12:57:14 +0000 |
755 | +++ qml/Launcher/Launcher.qml 2014-03-25 15:08:15 +0000 |
756 | @@ -29,7 +29,8 @@ |
757 | property int dragAreaWidth: units.gu(1) |
758 | property int minimizeDistance: units.gu(26) |
759 | property real progress: dragArea.dragging && dragArea.touchX > panelWidth ? |
760 | - (width * (dragArea.touchX-panelWidth) / (width - panelWidth)) : 0 |
761 | + (width * (dragArea.touchX-panelWidth) / (width - panelWidth)) : |
762 | + (dragArea.dragging ? 0.001 : 0) |
763 | |
764 | readonly property bool shown: panel.x > -panel.width |
765 | |
766 | |
767 | === modified file 'qml/Panel/Panel.qml' |
768 | --- qml/Panel/Panel.qml 2014-01-14 15:35:57 +0000 |
769 | +++ qml/Panel/Panel.qml 2014-03-25 15:08:15 +0000 |
770 | @@ -62,7 +62,7 @@ |
771 | height: __panelMinusSeparatorLineHeight |
772 | y: 0 |
773 | |
774 | - Behavior on y { StandardAnimation {} } |
775 | + Behavior on y { StandardAnimation { duration: UbuntuAnimation.FastDuration } } |
776 | } |
777 | |
778 | PanelSeparatorLine { |
779 | |
780 | === modified file 'qml/Shell.qml' |
781 | --- qml/Shell.qml 2014-03-19 22:21:57 +0000 |
782 | +++ qml/Shell.qml 2014-03-25 15:08:15 +0000 |
783 | @@ -31,7 +31,6 @@ |
784 | import "Hud" |
785 | import "Components" |
786 | import "Bottombar" |
787 | -import "SideStage" |
788 | import "Notifications" |
789 | import Unity.Notifications 1.0 as NotificationBackend |
790 | |
791 | @@ -49,20 +48,24 @@ |
792 | readonly property real panelHeight: panel.panelHeight |
793 | |
794 | property bool dashShown: dash.shown |
795 | - property bool stageScreenshotsReady: { |
796 | - if (sideStage.shown) { |
797 | - if (mainStage.applications.count > 0) { |
798 | - return mainStage.usingScreenshots && sideStage.usingScreenshots; |
799 | - } else { |
800 | - return sideStage.usingScreenshots; |
801 | + |
802 | + property bool sideStageEnabled: shell.width >= units.gu(60) |
803 | + readonly property string focusedApplicationId: ApplicationManager.focusedApplicationId |
804 | + |
805 | + function activateApplication(appId) { |
806 | + if (ApplicationManager.findApplication(appId)) { |
807 | + ApplicationManager.requestFocusApplication(appId); |
808 | + stages.show(); |
809 | + if (stages.locked && ApplicationManager.focusedApplicationId == appId) { |
810 | + applicationsDisplayLoader.item.select(appId); |
811 | } |
812 | } else { |
813 | - return mainStage.usingScreenshots; |
814 | + var execFlags = shell.sideStageEnabled ? ApplicationManager.NoFlag : ApplicationManager.ForceMainStage; |
815 | + ApplicationManager.startApplication(appId, execFlags); |
816 | + stages.show(); |
817 | } |
818 | } |
819 | |
820 | - property var applicationManager: ApplicationManagerWrapper {} |
821 | - |
822 | Binding { |
823 | target: LauncherModel |
824 | property: "applicationManager" |
825 | @@ -71,49 +74,6 @@ |
826 | |
827 | Component.onCompleted: { |
828 | Theme.name = "Ubuntu.Components.Themes.SuruGradient" |
829 | - |
830 | - applicationManager.sideStageEnabled = Qt.binding(function() { return sideStage.enabled }) |
831 | - |
832 | - // FIXME: if application focused before shell starts, shell draws on top of it only. |
833 | - // We should detect already running applications on shell start and bring them to the front. |
834 | - applicationManager.unfocusCurrentApplication(); |
835 | - } |
836 | - |
837 | - readonly property bool applicationFocused: !!applicationManager.mainStageFocusedApplication |
838 | - || !!applicationManager.sideStageFocusedApplication |
839 | - // Used for autopilot testing. |
840 | - readonly property string currentFocusedAppId: ApplicationManager.focusedApplicationId |
841 | - |
842 | - readonly property bool fullscreenMode: { |
843 | - if (greeter.shown || lockscreen.shown) { |
844 | - return false; |
845 | - } else if (mainStage.usingScreenshots) { // Window Manager animating so want to re-evaluate fullscreen mode |
846 | - return mainStage.switchingFromFullscreenToFullscreen; |
847 | - } else if (applicationManager.mainStageFocusedApplication) { |
848 | - return applicationManager.mainStageFocusedApplication.fullscreen; |
849 | - } else { |
850 | - return false; |
851 | - } |
852 | - } |
853 | - |
854 | - function activateApplication(appId, argument) { |
855 | - if (applicationManager) { |
856 | - // For newly started applications, as it takes them time to draw their first frame |
857 | - // we add a delay before we hide the animation screenshots to compensate. |
858 | - var addDelay = !applicationManager.getApplicationFromDesktopFile(appId); |
859 | - |
860 | - var application; |
861 | - application = applicationManager.activateApplication(appId, argument); |
862 | - if (application == null) { |
863 | - return; |
864 | - } |
865 | - if (application.stage == ApplicationInfo.MainStage || !sideStage.enabled) { |
866 | - mainStage.activateApplication(appId, addDelay); |
867 | - } else { |
868 | - sideStage.activateApplication(appId, addDelay); |
869 | - } |
870 | - stages.show(); |
871 | - } |
872 | } |
873 | |
874 | GSettings { |
875 | @@ -133,244 +93,219 @@ |
876 | Keys.onVolumeDownPressed: volumeControl.volumeDown() |
877 | |
878 | Item { |
879 | - id: underlay |
880 | - objectName: "underlay" |
881 | + id: underlayClipper |
882 | anchors.fill: parent |
883 | - |
884 | - // Whether the underlay is fully covered by opaque UI elements. |
885 | - property bool fullyCovered: panel.indicators.fullyOpened && shell.width <= panel.indicatorsMenuWidth |
886 | - |
887 | - readonly property bool applicationRunning: ((mainStage.applications && mainStage.applications.count > 0) |
888 | - || (sideStage.applications && sideStage.applications.count > 0)) |
889 | - |
890 | - // Whether the user should see the topmost application surface (if there's one at all). |
891 | - readonly property bool applicationSurfaceShouldBeSeen: applicationRunning && !stages.fullyHidden |
892 | - && !mainStage.usingScreenshots // but want sideStage animating over app surface |
893 | - |
894 | - |
895 | - |
896 | - // NB! Application surfaces are stacked behing the shell one. So they can only be seen by the user |
897 | - // through the translucent parts of the shell surface. |
898 | - visible: !fullyCovered && !applicationSurfaceShouldBeSeen |
899 | - |
900 | - Rectangle { |
901 | - anchors.fill: parent |
902 | - color: "black" |
903 | - opacity: dash.disappearingAnimationProgress |
904 | - } |
905 | - |
906 | - Image { |
907 | - anchors.fill: dash |
908 | - source: shell.width > shell.height ? "Dash/graphics/paper_landscape.png" : "Dash/graphics/paper_portrait.png" |
909 | - fillMode: Image.PreserveAspectCrop |
910 | - horizontalAlignment: Image.AlignRight |
911 | - verticalAlignment: Image.AlignTop |
912 | - } |
913 | - |
914 | - Dash { |
915 | - id: dash |
916 | - objectName: "dash" |
917 | - |
918 | - available: !greeter.shown && !lockscreen.shown |
919 | - hides: [stages, launcher, panel.indicators] |
920 | - shown: disappearingAnimationProgress !== 1.0 |
921 | - enabled: disappearingAnimationProgress === 0.0 && edgeDemo.dashEnabled |
922 | - // FIXME: unfocus all applications when going back to the dash |
923 | - onEnabledChanged: { |
924 | - if (enabled) { |
925 | - shell.applicationManager.unfocusCurrentApplication() |
926 | - } |
927 | - } |
928 | - |
929 | - anchors { |
930 | - fill: parent |
931 | - topMargin: panel.panelHeight |
932 | - } |
933 | - |
934 | - contentScale: 1.0 - 0.2 * disappearingAnimationProgress |
935 | - opacity: 1.0 - disappearingAnimationProgress |
936 | - property real disappearingAnimationProgress: { |
937 | - if (greeter.shown) { |
938 | - return greeter.showProgress; |
939 | + anchors.rightMargin: stages.overlayWidth |
940 | + clip: stages.overlayMode && !stages.painting |
941 | + |
942 | + InputFilterArea { |
943 | + anchors.fill: parent |
944 | + blockInput: parent.clip |
945 | + } |
946 | + |
947 | + Item { |
948 | + id: underlay |
949 | + objectName: "underlay" |
950 | + anchors.fill: parent |
951 | + anchors.rightMargin: -parent.anchors.rightMargin |
952 | + |
953 | + // Whether the underlay is fully covered by opaque UI elements. |
954 | + property bool fullyCovered: panel.indicators.fullyOpened && shell.width <= panel.indicatorsMenuWidth |
955 | + |
956 | + // Whether the user should see the topmost application surface (if there's one at all). |
957 | + readonly property bool applicationSurfaceShouldBeSeen: stages.shown && !stages.painting && !stages.overlayMode |
958 | + |
959 | + // NB! Application surfaces are stacked behind the shell one. So they can only be seen by the user |
960 | + // through the translucent parts of the shell surface. |
961 | + visible: !fullyCovered && !applicationSurfaceShouldBeSeen |
962 | + |
963 | + CrossFadeImage { |
964 | + id: backgroundImage |
965 | + objectName: "backgroundImage" |
966 | + |
967 | + anchors.fill: parent |
968 | + source: shell.background |
969 | + fillMode: Image.PreserveAspectCrop |
970 | + } |
971 | + |
972 | + Rectangle { |
973 | + anchors.fill: parent |
974 | + color: "black" |
975 | + opacity: dash.disappearingAnimationProgress |
976 | + } |
977 | + |
978 | + Image { |
979 | + anchors.fill: dash |
980 | + source: shell.width > shell.height ? "Dash/graphics/paper_landscape.png" : "Dash/graphics/paper_portrait.png" |
981 | + fillMode: Image.PreserveAspectCrop |
982 | + horizontalAlignment: Image.AlignRight |
983 | + verticalAlignment: Image.AlignTop |
984 | + } |
985 | + |
986 | + Dash { |
987 | + id: dash |
988 | + objectName: "dash" |
989 | + |
990 | + available: !greeter.shown && !lockscreen.shown |
991 | + hides: [stages, launcher, panel.indicators] |
992 | + shown: disappearingAnimationProgress !== 1.0 |
993 | + enabled: disappearingAnimationProgress === 0.0 && edgeDemo.dashEnabled |
994 | + |
995 | + anchors { |
996 | + fill: parent |
997 | + topMargin: panel.panelHeight |
998 | + } |
999 | + |
1000 | + contentScale: 1.0 - 0.2 * disappearingAnimationProgress |
1001 | + opacity: 1.0 - disappearingAnimationProgress |
1002 | + property real disappearingAnimationProgress: { |
1003 | + if (greeter.shown) { |
1004 | + return greeter.showProgress; |
1005 | + } else { |
1006 | + if (stages.overlayMode) { |
1007 | + return 0; |
1008 | + } |
1009 | + return stages.showProgress |
1010 | + } |
1011 | + } |
1012 | + |
1013 | + // FIXME: only necessary because stages.showProgress and |
1014 | + // greeterRevealer.animatedProgress are not animated |
1015 | + Behavior on disappearingAnimationProgress { SmoothedAnimation { velocity: 5 }} |
1016 | + } |
1017 | + } |
1018 | + } |
1019 | + |
1020 | + EdgeDragArea { |
1021 | + id: stagesDragHandle |
1022 | + direction: Direction.Leftwards |
1023 | + |
1024 | + anchors { top: parent.top; right: parent.right; bottom: parent.bottom } |
1025 | + width: shell.edgeSize |
1026 | + |
1027 | + property real progress: stages.width |
1028 | + |
1029 | + onTouchXChanged: { |
1030 | + if (status == DirectionalDragArea.Recognized) { |
1031 | + if (ApplicationManager.count == 0) { |
1032 | + progress = Math.max(stages.width - stagesDragHandle.width + touchX, stages.width * .3) |
1033 | } else { |
1034 | - return stagesOuterContainer.showProgress; |
1035 | + progress = stages.width - stagesDragHandle.width + touchX |
1036 | } |
1037 | } |
1038 | + } |
1039 | |
1040 | - // FIXME: only necessary because stagesOuterContainer.showProgress and |
1041 | - // greeterRevealer.animatedProgress are not animated |
1042 | - Behavior on disappearingAnimationProgress { SmoothedAnimation { velocity: 5 }} |
1043 | + onDraggingChanged: { |
1044 | + if (!dragging) { |
1045 | + if (ApplicationManager.count > 0 && progress < stages.width - units.gu(10)) { |
1046 | + stages.show() |
1047 | + } |
1048 | + stagesDragHandle.progress = stages.width; |
1049 | + } |
1050 | } |
1051 | } |
1052 | |
1053 | Item { |
1054 | - id: stagesOuterContainer |
1055 | - |
1056 | + id: stages |
1057 | + objectName: "stages" |
1058 | width: parent.width |
1059 | height: parent.height |
1060 | - x: launcher.progress |
1061 | - Behavior on x {SmoothedAnimation{velocity: 600}} |
1062 | - |
1063 | - property real showProgress: |
1064 | - MathUtils.clamp(1 - (x + stages.x) / shell.width, 0, 1) |
1065 | - |
1066 | - Showable { |
1067 | - id: stages |
1068 | - objectName: "stages" |
1069 | - |
1070 | - x: width |
1071 | - |
1072 | - property bool fullyShown: shown && x == 0 && parent.x == 0 |
1073 | - property bool fullyHidden: !shown && x == width |
1074 | - available: !greeter.shown |
1075 | - hides: [panel.indicators] |
1076 | - shown: false |
1077 | - opacity: 1.0 |
1078 | - showAnimation: StandardAnimation { property: "x"; duration: 350; to: 0; easing.type: Easing.OutCubic } |
1079 | - hideAnimation: StandardAnimation { property: "x"; duration: 350; to: width; easing.type: Easing.OutCubic } |
1080 | - |
1081 | - width: parent.width |
1082 | - height: parent.height |
1083 | - |
1084 | - // close the stages when no focused application remains |
1085 | - Connections { |
1086 | - target: shell.applicationManager |
1087 | - onMainStageFocusedApplicationChanged: stages.closeIfNoApplications() |
1088 | - onSideStageFocusedApplicationChanged: stages.closeIfNoApplications() |
1089 | - ignoreUnknownSignals: true |
1090 | - } |
1091 | - |
1092 | - function closeIfNoApplications() { |
1093 | - if (!shell.applicationManager.mainStageFocusedApplication |
1094 | - && !shell.applicationManager.sideStageFocusedApplication |
1095 | - && shell.applicationManager.mainStageApplications.count == 0 |
1096 | - && shell.applicationManager.sideStageApplications.count == 0) { |
1097 | - stages.hide(); |
1098 | - } |
1099 | - } |
1100 | - |
1101 | - // show the stages when an application gets the focus |
1102 | - Connections { |
1103 | - target: shell.applicationManager |
1104 | - onMainStageFocusedApplicationChanged: { |
1105 | - if (shell.applicationManager.mainStageFocusedApplication) { |
1106 | - mainStage.show(); |
1107 | - stages.show(); |
1108 | - } |
1109 | - } |
1110 | - onSideStageFocusedApplicationChanged: { |
1111 | - if (shell.applicationManager.sideStageFocusedApplication) { |
1112 | - sideStage.show(); |
1113 | - stages.show(); |
1114 | - } |
1115 | - } |
1116 | - ignoreUnknownSignals: true |
1117 | - } |
1118 | - |
1119 | - Stage { |
1120 | - id: mainStage |
1121 | - |
1122 | - anchors.fill: parent |
1123 | - fullyShown: stages.fullyShown |
1124 | - fullyHidden: stages.fullyHidden |
1125 | - shouldUseScreenshots: !fullyShown |
1126 | - rightEdgeEnabled: !sideStage.enabled |
1127 | - |
1128 | - applicationManager: shell.applicationManager |
1129 | - rightEdgeDraggingAreaWidth: shell.edgeSize |
1130 | - normalApplicationY: shell.panelHeight |
1131 | - |
1132 | - shown: true |
1133 | - function show() { |
1134 | + |
1135 | + x: { |
1136 | + if (shown) { |
1137 | + if (overlayMode || locked) { |
1138 | + return 0; |
1139 | + } |
1140 | + return launcher.progress |
1141 | + } else { |
1142 | + return stagesDragHandle.progress |
1143 | + } |
1144 | + } |
1145 | + |
1146 | + Behavior on x { SmoothedAnimation { velocity: 600; duration: UbuntuAnimation.FastDuration } } |
1147 | + |
1148 | + property bool shown: false |
1149 | + |
1150 | + property real showProgress: overlayMode ? 0 : MathUtils.clamp(1 - x / shell.width, 0, 1) |
1151 | + |
1152 | + property bool fullyShown: x == 0 |
1153 | + property bool fullyHidden: x == width |
1154 | + |
1155 | + property bool painting: applicationsDisplayLoader.item ? applicationsDisplayLoader.item.painting : false |
1156 | + property bool fullscreen: applicationsDisplayLoader.item ? applicationsDisplayLoader.item.fullscreen : false |
1157 | + property bool overlayMode: applicationsDisplayLoader.item ? applicationsDisplayLoader.item.overlayMode : false |
1158 | + property int overlayWidth: applicationsDisplayLoader.item ? applicationsDisplayLoader.item.overlayWidth : false |
1159 | + property bool locked: applicationsDisplayLoader.item ? applicationsDisplayLoader.item.locked : false |
1160 | + |
1161 | + function show() { |
1162 | + shown = true; |
1163 | + panel.indicators.hide(); |
1164 | + if (!ApplicationManager.focusedApplicationId && ApplicationManager.count > 0) { |
1165 | + ApplicationManager.focusApplication(ApplicationManager.get(0).appId); |
1166 | + } |
1167 | + } |
1168 | + |
1169 | + function hide() { |
1170 | + shown = false; |
1171 | + if (ApplicationManager.focusedApplicationId) { |
1172 | + ApplicationManager.unfocusCurrentApplication(); |
1173 | + } |
1174 | + } |
1175 | + |
1176 | + Connections { |
1177 | + target: ApplicationManager |
1178 | + |
1179 | + onFocusRequested: { |
1180 | + stages.show(); |
1181 | + } |
1182 | + |
1183 | + onFocusedApplicationIdChanged: { |
1184 | + if (ApplicationManager.focusedApplicationId.length > 0) { |
1185 | stages.show(); |
1186 | - } |
1187 | - function hide() { |
1188 | - } |
1189 | - |
1190 | - // FIXME: workaround the fact that focusing a main stage application |
1191 | - // raises its surface on top of all other surfaces including the ones |
1192 | - // that belong to side stage applications. |
1193 | - onFocusedApplicationChanged: { |
1194 | - if (focusedApplication && sideStage.focusedApplication && sideStage.fullyShown) { |
1195 | - shell.applicationManager.focusApplication(sideStage.focusedApplication); |
1196 | - } |
1197 | - } |
1198 | - } |
1199 | - |
1200 | - SideStage { |
1201 | - id: sideStage |
1202 | - |
1203 | - applicationManager: shell.applicationManager |
1204 | - rightEdgeDraggingAreaWidth: shell.edgeSize |
1205 | - normalApplicationY: shell.panelHeight |
1206 | - |
1207 | - onShownChanged: { |
1208 | - if (!shown && mainStage.applications.count == 0) { |
1209 | + } else { |
1210 | + if (!stages.overlayMode) { |
1211 | stages.hide(); |
1212 | } |
1213 | } |
1214 | - // FIXME: when hiding the side stage, refocus the main stage |
1215 | - // application so that it goes in front of the side stage |
1216 | - // application and hides it |
1217 | - onFullyShownChanged: { |
1218 | - if (!fullyShown && stages.fullyShown && sideStage.focusedApplication != null) { |
1219 | - shell.applicationManager.focusApplication(mainStage.focusedApplication); |
1220 | - } |
1221 | + |
1222 | + // If any app is focused when greeter is open, it's due to a user action |
1223 | + // like a snap decision (say, an incoming call). |
1224 | + // TODO: these should be protected to only unlock for certain applications / certain usecases |
1225 | + // potentially only in connection with a notification. |
1226 | + greeter.hide() |
1227 | + } |
1228 | + |
1229 | + onApplicationAdded: { |
1230 | + stages.show(); |
1231 | + } |
1232 | + |
1233 | + onApplicationRemoved: { |
1234 | + if (ApplicationManager.focusedApplicationId.length == 0) { |
1235 | + stages.hide(); |
1236 | } |
1237 | - |
1238 | - enabled: shell.width >= units.gu(100) |
1239 | - visible: enabled |
1240 | - fullyShown: stages.fullyShown && shown |
1241 | - && sideStage[sideStageRevealer.boundProperty] == sideStageRevealer.openedValue |
1242 | - shouldUseScreenshots: !fullyShown || mainStage.usingScreenshots || sideStageRevealer.pressed |
1243 | - |
1244 | - available: !greeter.shown && !lockscreen.shown && enabled |
1245 | - hides: [launcher, panel.indicators] |
1246 | - shown: false |
1247 | - showAnimation: StandardAnimation { property: "x"; duration: 350; to: sideStageRevealer.openedValue; easing.type: Easing.OutQuint } |
1248 | - hideAnimation: StandardAnimation { property: "x"; duration: 350; to: sideStageRevealer.closedValue; easing.type: Easing.OutQuint } |
1249 | - |
1250 | - width: units.gu(40) |
1251 | - height: stages.height |
1252 | - handleExpanded: sideStageRevealer.pressed |
1253 | - } |
1254 | - |
1255 | - Revealer { |
1256 | - id: sideStageRevealer |
1257 | - |
1258 | - enabled: mainStage.applications.count > 0 && sideStage.applications.count > 0 |
1259 | - && sideStage.available |
1260 | - direction: Qt.RightToLeft |
1261 | - openedValue: parent.width - sideStage.width |
1262 | - hintDisplacement: units.gu(3) |
1263 | - /* The size of the sidestage handle needs to be bigger than the |
1264 | - typical size used for edge detection otherwise it is really |
1265 | - hard to grab. |
1266 | - */ |
1267 | - handleSize: sideStage.shown ? units.gu(4) : shell.edgeSize |
1268 | - closedValue: parent.width + sideStage.handleSizeCollapsed |
1269 | - target: sideStage |
1270 | - x: parent.width - width |
1271 | - width: sideStage.width + handleSize * 0.7 |
1272 | - height: sideStage.height |
1273 | - orientation: Qt.Horizontal |
1274 | - } |
1275 | - |
1276 | - DragHandle { |
1277 | - id: stagesDragHandle |
1278 | - |
1279 | - anchors.top: parent.top |
1280 | - anchors.bottom: parent.bottom |
1281 | - anchors.right: parent.left |
1282 | - |
1283 | - width: shell.edgeSize |
1284 | - direction: Direction.Leftwards |
1285 | - enabled: greeter.showProgress == 0 && edgeDemo.dashEnabled |
1286 | - property bool haveApps: mainStage.applications.count > 0 || sideStage.applications.count > 0 |
1287 | - |
1288 | - maxTotalDragDistance: haveApps ? parent.width : parent.width * 0.7 |
1289 | - // Make autocompletion impossible when !haveApps |
1290 | - edgeDragEvaluator.minDragDistance: haveApps ? maxTotalDragDistance * 0.1 : Number.MAX_VALUE |
1291 | + } |
1292 | + } |
1293 | + |
1294 | + Loader { |
1295 | + id: applicationsDisplayLoader |
1296 | + anchors.fill: parent |
1297 | + |
1298 | + source: shell.sideStageEnabled ? "Stages/StageWithSideStage.qml" : "Stages/PhoneStage.qml" |
1299 | + |
1300 | + Binding { |
1301 | + target: applicationsDisplayLoader.item |
1302 | + property: "moving" |
1303 | + value: !stages.fullyShown |
1304 | + } |
1305 | + Binding { |
1306 | + target: applicationsDisplayLoader.item |
1307 | + property: "shown" |
1308 | + value: stages.shown |
1309 | + } |
1310 | + Binding { |
1311 | + target: applicationsDisplayLoader.item |
1312 | + property: "dragAreaWidth" |
1313 | + value: shell.edgeSize |
1314 | } |
1315 | } |
1316 | } |
1317 | @@ -447,26 +382,6 @@ |
1318 | |
1319 | dragHandleWidth: shell.edgeSize |
1320 | |
1321 | - property var previousMainApp: null |
1322 | - property var previousSideApp: null |
1323 | - |
1324 | - function removeApplicationFocus() { |
1325 | - greeter.previousMainApp = applicationManager.mainStageFocusedApplication; |
1326 | - greeter.previousSideApp = applicationManager.sideStageFocusedApplication; |
1327 | - applicationManager.unfocusCurrentApplication(); |
1328 | - } |
1329 | - |
1330 | - function restoreApplicationFocus() { |
1331 | - if (greeter.previousMainApp) { |
1332 | - applicationManager.focusApplication(greeter.previousMainApp); |
1333 | - greeter.previousMainApp = null; |
1334 | - } |
1335 | - if (greeter.previousSideApp) { |
1336 | - applicationManager.focusApplication(greeter.previousSideApp); |
1337 | - greeter.previousSideApp = null; |
1338 | - } |
1339 | - } |
1340 | - |
1341 | onShownChanged: { |
1342 | if (shown) { |
1343 | lockscreen.reset(); |
1344 | @@ -476,9 +391,6 @@ |
1345 | LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole)); |
1346 | } |
1347 | greeter.forceActiveFocus(); |
1348 | - removeApplicationFocus(); |
1349 | - } else { |
1350 | - restoreApplicationFocus(); |
1351 | } |
1352 | } |
1353 | |
1354 | @@ -496,33 +408,16 @@ |
1355 | } |
1356 | } |
1357 | |
1358 | - Connections { |
1359 | - target: applicationManager |
1360 | - ignoreUnknownSignals: true |
1361 | - // If any app is focused when greeter is open, it's due to a user action |
1362 | - // like a snap decision (say, an incoming call). |
1363 | - // TODO: these should be protected to only unlock for certain applications / certain usecases |
1364 | - // potentially only in connection with a notification. |
1365 | - onMainStageFocusedApplicationChanged: { |
1366 | - if (greeter.shown && applicationManager.mainStageFocusedApplication) { |
1367 | - greeter.previousMainApp = null // make way for new focused app |
1368 | - greeter.previousSideApp = null |
1369 | - greeter.hide() |
1370 | - } |
1371 | - } |
1372 | - onSideStageFocusedApplicationChanged: { |
1373 | - if (greeter.shown && applicationManager.sideStageFocusedApplication) { |
1374 | - greeter.previousMainApp = null // make way for new focused app |
1375 | - greeter.previousSideApp = null |
1376 | - greeter.hide() |
1377 | - } |
1378 | - } |
1379 | + Binding { |
1380 | + target: ApplicationManager |
1381 | + property: "suspended" |
1382 | + value: greeter.shown && greeter.showProgress == 1 |
1383 | } |
1384 | } |
1385 | |
1386 | InputFilterArea { |
1387 | anchors.fill: parent |
1388 | - blockInput: !applicationFocused || greeter.shown || lockscreen.shown || launcher.shown |
1389 | + blockInput: ApplicationManager.focusedApplicationId.length === 0 || greeter.shown || lockscreen.shown || launcher.shown |
1390 | || panel.indicators.shown || hud.shown |
1391 | } |
1392 | |
1393 | @@ -571,7 +466,9 @@ |
1394 | available: edgeDemo.panelEnabled |
1395 | contentEnabled: edgeDemo.panelContentEnabled |
1396 | } |
1397 | - fullscreenMode: shell.fullscreenMode |
1398 | + property string focusedAppId: ApplicationManager.focusedApplicationId |
1399 | + property var focusedApplication: ApplicationManager.findApplication(focusedAppId) |
1400 | + fullscreenMode: focusedApplication && stages.fullscreen && !greeter.shown && !lockscreen.shown |
1401 | searchVisible: !greeter.shown && !lockscreen.shown && dash.shown && dash.searchable |
1402 | |
1403 | InputFilterArea { |
1404 | @@ -597,9 +494,8 @@ |
1405 | hideAnimation: StandardAnimation { property: "y"; duration: hud.showableAnimationDuration; to: hudRevealer.closedValue; easing.type: Easing.Linear } |
1406 | |
1407 | Connections { |
1408 | - target: shell.applicationManager |
1409 | - onMainStageFocusedApplicationChanged: hud.hide() |
1410 | - onSideStageFocusedApplicationChanged: hud.hide() |
1411 | + target: ApplicationManager |
1412 | + onFocusedApplicationIdChanged: hud.hide() |
1413 | } |
1414 | } |
1415 | |
1416 | @@ -624,7 +520,7 @@ |
1417 | theHud: hud |
1418 | anchors.fill: parent |
1419 | enabled: hud.available |
1420 | - applicationIsOnForeground: applicationFocused |
1421 | + applicationIsOnForeground: ApplicationManager.focusedApplicationId |
1422 | } |
1423 | |
1424 | InputFilterArea { |
1425 | @@ -655,9 +551,11 @@ |
1426 | showHome() |
1427 | } |
1428 | onDash: { |
1429 | - if (stages.shown) { |
1430 | - stages.hide(); |
1431 | - launcher.hide(); |
1432 | + if (stages.shown && !stages.overlayMode) { |
1433 | + if (!stages.locked) { |
1434 | + stages.hide(); |
1435 | + launcher.hide(); |
1436 | + } |
1437 | } |
1438 | } |
1439 | onDashSwipeChanged: if (dashSwipe && stages.shown) dash.setCurrentScope("clickscope", false, true) |
1440 | @@ -750,14 +648,14 @@ |
1441 | anchors.bottom: parent.bottom |
1442 | anchors.left: parent.left |
1443 | anchors.right: parent.right |
1444 | - height: shell.applicationManager ? shell.applicationManager.keyboardHeight : 0 |
1445 | + height: ApplicationManager.keyboardVisible ? ApplicationManager.keyboardHeight : 0 |
1446 | |
1447 | - enabled: shell.applicationManager && shell.applicationManager.keyboardVisible |
1448 | + enabled: ApplicationManager.keyboardVisible |
1449 | } |
1450 | |
1451 | Label { |
1452 | anchors.centerIn: parent |
1453 | - visible: applicationManager.fake |
1454 | + visible: ApplicationManager.fake ? ApplicationManager.fake : false |
1455 | text: "EARLY ALPHA\nNOT READY FOR USE" |
1456 | color: "lightgrey" |
1457 | opacity: 0.2 |
1458 | |
1459 | === removed directory 'qml/SideStage' |
1460 | === removed file 'qml/SideStage/SideStage.qml' |
1461 | --- qml/SideStage/SideStage.qml 2014-02-03 13:31:28 +0000 |
1462 | +++ qml/SideStage/SideStage.qml 1970-01-01 00:00:00 +0000 |
1463 | @@ -1,73 +0,0 @@ |
1464 | -/* |
1465 | - * Copyright (C) 2013 Canonical, Ltd. |
1466 | - * |
1467 | - * This program is free software; you can redistribute it and/or modify |
1468 | - * it under the terms of the GNU General Public License as published by |
1469 | - * the Free Software Foundation; version 3. |
1470 | - * |
1471 | - * This program is distributed in the hope that it will be useful, |
1472 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1473 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1474 | - * GNU General Public License for more details. |
1475 | - * |
1476 | - * You should have received a copy of the GNU General Public License |
1477 | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1478 | - */ |
1479 | - |
1480 | -import QtQuick 2.0 |
1481 | -import Unity.Application 0.1 |
1482 | -import Ubuntu.Components 0.1 |
1483 | -import "../Components" |
1484 | - |
1485 | -Stage { |
1486 | - id: stage |
1487 | - |
1488 | - type: ApplicationInfo.SideStage |
1489 | - property real handleSizeCollapsed: units.gu(2.5) |
1490 | - property real handleSizeExpanded: units.gu(4) |
1491 | - property bool handleExpanded |
1492 | - |
1493 | - /* FIXME: workaround so that when a main stage app goes fullscreen |
1494 | - the sidestage's top is not transparent. Proper fix would be to |
1495 | - resize the side stage app. |
1496 | - */ |
1497 | - Rectangle { |
1498 | - id: backgroundBeneathPanel |
1499 | - anchors { |
1500 | - top: parent.top |
1501 | - left: parent.left |
1502 | - right: parent.right |
1503 | - } |
1504 | - height: shell.panelHeight |
1505 | - color: background.color |
1506 | - z: -1 |
1507 | - } |
1508 | - |
1509 | - Rectangle { |
1510 | - id: background |
1511 | - anchors.fill: parent |
1512 | - color: "#2c2924" |
1513 | - z: -1 |
1514 | - visible: stage.usingScreenshots |
1515 | - } |
1516 | - |
1517 | - SidestageHandle { |
1518 | - id: handle |
1519 | - objectName: "sideStageHandle" |
1520 | - |
1521 | - anchors { |
1522 | - top: parent.top |
1523 | - bottom: parent.bottom |
1524 | - left: parent.left |
1525 | - leftMargin: -width |
1526 | - } |
1527 | - width: handleExpanded ? handleSizeExpanded : handleSizeCollapsed |
1528 | - Behavior on width { NumberAnimation { easing.type: Easing.OutQuart} } |
1529 | - z: -1 |
1530 | - } |
1531 | - |
1532 | - InputFilterArea { |
1533 | - anchors.fill: handle |
1534 | - blockInput: visible |
1535 | - } |
1536 | -} |
1537 | |
1538 | === removed directory 'qml/SideStage/graphics' |
1539 | === added directory 'qml/Stages' |
1540 | === added file 'qml/Stages/PhoneStage.qml' |
1541 | --- qml/Stages/PhoneStage.qml 1970-01-01 00:00:00 +0000 |
1542 | +++ qml/Stages/PhoneStage.qml 2014-03-25 15:08:15 +0000 |
1543 | @@ -0,0 +1,501 @@ |
1544 | +/* |
1545 | + * Copyright (C) 2014 Canonical, Ltd. |
1546 | + * |
1547 | + * This program is free software; you can redistribute it and/or modify |
1548 | + * it under the terms of the GNU General Public License as published by |
1549 | + * the Free Software Foundation; version 3. |
1550 | + * |
1551 | + * This program is distributed in the hope that it will be useful, |
1552 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1553 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1554 | + * GNU General Public License for more details. |
1555 | + * |
1556 | + * You should have received a copy of the GNU General Public License |
1557 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1558 | + */ |
1559 | + |
1560 | +import QtQuick 2.0 |
1561 | +import Ubuntu.Components 0.1 |
1562 | +import Ubuntu.Gestures 0.1 |
1563 | +import Unity.Application 0.1 |
1564 | +import Utils 0.1 |
1565 | +import "../Components" |
1566 | + |
1567 | +Item { |
1568 | + id: root |
1569 | + |
1570 | + // Controls to be set from outside |
1571 | + property bool shown: false |
1572 | + property bool moving: false |
1573 | + property int dragAreaWidth |
1574 | + |
1575 | + // State information propagated to the outside |
1576 | + readonly property bool painting: mainScreenshotImage.visible || fadeInScreenshotImage.visible || appSplash.visible || spreadView.visible |
1577 | + property bool fullscreen: priv.focusedApplication ? priv.focusedApplication.fullscreen : false |
1578 | + property bool locked: spreadView.visible |
1579 | + |
1580 | + // Not used for PhoneStage, only useful for SideStage and similar |
1581 | + property bool overlayMode: false |
1582 | + property int overlayWidth: 0 |
1583 | + |
1584 | + function select(appId) { |
1585 | + spreadView.snapTo(priv.indexOf(appId)) |
1586 | + } |
1587 | + |
1588 | + onMovingChanged: { |
1589 | + if (moving) { |
1590 | + if (ApplicationManager.focusedApplicationId) { |
1591 | + priv.requestNewScreenshot(); |
1592 | + } else { |
1593 | + mainScreenshotImage.anchors.leftMargin = 0; |
1594 | + mainScreenshotImage.source = ApplicationManager.get(0).screenshot; |
1595 | + mainScreenshotImage.visible = true; |
1596 | + } |
1597 | + } else { |
1598 | + mainScreenshotImage.visible = false; |
1599 | + } |
1600 | + } |
1601 | + |
1602 | + Connections { |
1603 | + target: ApplicationManager |
1604 | + |
1605 | + onFocusRequested: { |
1606 | + if (spreadView.visible) { |
1607 | + spreadView.snapTo(priv.indexOf(appId)); |
1608 | + } else { |
1609 | + priv.switchToApp(appId); |
1610 | + } |
1611 | + } |
1612 | + |
1613 | + onFocusedApplicationIdChanged: { |
1614 | + if (ApplicationManager.focusedApplicationId.length > 0) { |
1615 | + if (priv.secondApplicationStarting || priv.applicationStarting) { |
1616 | + appSplashTimer.start(); |
1617 | + } else { |
1618 | + var application = priv.focusedApplication; |
1619 | + root.fullscreen = application.fullscreen; |
1620 | + mainScreenshotImage.source = application.screenshot; |
1621 | + } |
1622 | + } else { |
1623 | + spreadView.selectedIndex = -1; |
1624 | + spreadView.phase = 0; |
1625 | + spreadView.contentX = -spreadView.shift; |
1626 | + } |
1627 | + } |
1628 | + |
1629 | + onApplicationAdded: { |
1630 | + if (!priv.focusedApplication) { |
1631 | + mainScreenshotImage.source = ""; |
1632 | + mainScreenshotImage.visible = false; |
1633 | + priv.applicationStarting = true; |
1634 | + } else { |
1635 | + mainScreenshotImage.source = ""; |
1636 | + priv.newFocusedAppId = appId; |
1637 | + priv.secondApplicationStarting = true; |
1638 | + priv.requestNewScreenshot(); |
1639 | + } |
1640 | + |
1641 | + if (spreadView.visible) { |
1642 | + spreadView.snapTo(0); |
1643 | + } |
1644 | + } |
1645 | + |
1646 | + onApplicationRemoved: { |
1647 | + if (ApplicationManager.count == 0) { |
1648 | + mainScreenshotImage.source = "" |
1649 | + mainScreenshotImage.visible = false; |
1650 | + } else { |
1651 | + mainScreenshotImage.source = ApplicationManager.get(0).screenshot; |
1652 | + } |
1653 | + } |
1654 | + } |
1655 | + |
1656 | + QtObject { |
1657 | + id: priv |
1658 | + |
1659 | + property string focusedAppId: ApplicationManager.focusedApplicationId |
1660 | + property var focusedApplication: ApplicationManager.findApplication(focusedAppId) |
1661 | + property url focusedScreenshot: focusedApplication ? focusedApplication.screenshot : "" |
1662 | + |
1663 | + property bool waitingForScreenshot: false |
1664 | + |
1665 | + property bool applicationStarting: false |
1666 | + property bool secondApplicationStarting: false |
1667 | + |
1668 | + property string newFocusedAppId |
1669 | + |
1670 | + onFocusedScreenshotChanged: { |
1671 | + if (root.moving && priv.waitingForScreenshot) { |
1672 | + mainScreenshotImage.anchors.leftMargin = 0; |
1673 | + mainScreenshotImage.source = priv.focusedScreenshot |
1674 | + mainScreenshotImage.visible = true; |
1675 | + } else if (priv.secondApplicationStarting && priv.waitingForScreenshot) { |
1676 | + applicationSwitchingAnimation.start(); |
1677 | + } |
1678 | + waitingForScreenshot = false; |
1679 | + } |
1680 | + |
1681 | + function requestNewScreenshot() { |
1682 | + waitingForScreenshot = true; |
1683 | + ApplicationManager.updateScreenshot(focusedAppId); |
1684 | + } |
1685 | + |
1686 | + function switchToApp(appId) { |
1687 | + if (priv.focusedAppId) { |
1688 | + priv.newFocusedAppId = appId; |
1689 | + root.fullscreen = ApplicationManager.findApplication(appId).fullscreen; |
1690 | + applicationSwitchingAnimation.start(); |
1691 | + } else { |
1692 | + ApplicationManager.focusApplication(appId); |
1693 | + } |
1694 | + } |
1695 | + |
1696 | + function indexOf(appId) { |
1697 | + for (var i = 0; i < ApplicationManager.count; i++) { |
1698 | + if (ApplicationManager.get(i).appId == appId) { |
1699 | + return i; |
1700 | + } |
1701 | + } |
1702 | + return -1; |
1703 | + } |
1704 | + |
1705 | + } |
1706 | + |
1707 | + // FIXME: the signal connections seems to get lost. |
1708 | + Connections { |
1709 | + target: priv.focusedApplication |
1710 | + onScreenshotChanged: priv.focusedScreenshot = priv.focusedApplication.screenshot |
1711 | + } |
1712 | + Binding { |
1713 | + target: root |
1714 | + property: "fullscreen" |
1715 | + value: priv.focusedApplication ? priv.focusedApplication.fullscreen : false |
1716 | + } |
1717 | + |
1718 | + Timer { |
1719 | + id: appSplashTimer |
1720 | + // FIXME: apart from removing this completely in the future and make the app surface paint |
1721 | + // meaningful stuff, also check for colin's stuff to land so we can shape 1.4 secs away from here |
1722 | + // https://code.launchpad.net/~cjwatson/upstart-app-launch/libclick-manifest/+merge/210520 |
1723 | + // https://code.launchpad.net/~cjwatson/upstart-app-launch/libclick-pkgdir/+merge/209909 |
1724 | + interval: 1700 |
1725 | + repeat: false |
1726 | + onTriggered: { |
1727 | + priv.applicationStarting = false; |
1728 | + priv.secondApplicationStarting = false; |
1729 | + } |
1730 | + } |
1731 | + |
1732 | + SequentialAnimation { |
1733 | + id: applicationSwitchingAnimation |
1734 | + // setup |
1735 | + PropertyAction { target: mainScreenshotImage; property: "anchors.leftMargin"; value: 0 } |
1736 | + PropertyAction { target: mainScreenshotImage; property: "source"; value: priv.focusedScreenshot } |
1737 | + PropertyAction { targets: [mainScreenshotImage, fadeInScreenshotImage]; property: "visible"; value: true } |
1738 | + PropertyAction { target: fadeInScreenshotImage; property: "source"; value: { |
1739 | + var newFocusedApp = ApplicationManager.findApplication(priv.newFocusedAppId); |
1740 | + return newFocusedApp ? newFocusedApp.screenshot : "" } |
1741 | + } |
1742 | + PropertyAction { target: fadeInScreenshotImage; property: "opacity"; value: 0 } |
1743 | + PropertyAction { target: fadeInScreenshotImage; property: "scale"; value: .8 } |
1744 | + |
1745 | + |
1746 | + // The actual animation |
1747 | + ParallelAnimation { |
1748 | + UbuntuNumberAnimation { target: mainScreenshotImage; property: "anchors.leftMargin"; to: root.width; duration: UbuntuAnimation.SlowDuration } |
1749 | + UbuntuNumberAnimation { target: fadeInScreenshotImage; properties: "opacity,scale"; to: 1; duration: UbuntuAnimation.SlowDuration } |
1750 | + } |
1751 | + |
1752 | + // restore stuff |
1753 | + ScriptAction { script: ApplicationManager.focusApplication(priv.newFocusedAppId); } |
1754 | + PropertyAction { target: fadeInScreenshotImage; property: "visible"; value: false } |
1755 | + PropertyAction { target: mainScreenshotImage; property: "visible"; value: false } |
1756 | + } |
1757 | + |
1758 | + // FIXME: Drop this and make the imageprovider show a splashscreen instead |
1759 | + Rectangle { |
1760 | + id: appSplash2 |
1761 | + anchors.fill: parent |
1762 | + color: "white" |
1763 | + visible: priv.secondApplicationStarting |
1764 | + } |
1765 | + Image { |
1766 | + id: fadeInScreenshotImage |
1767 | + anchors { left: parent.left; bottom: parent.bottom } |
1768 | + width: parent.width |
1769 | + scale: .7 |
1770 | + visible: false |
1771 | + } |
1772 | + |
1773 | + Rectangle { |
1774 | + id: appSplash |
1775 | + anchors.fill: parent |
1776 | + color: "white" |
1777 | + visible: priv.applicationStarting |
1778 | + } |
1779 | + Image { |
1780 | + id: mainScreenshotImage |
1781 | + anchors { left: parent.left; bottom: parent.bottom } |
1782 | + width: parent.width |
1783 | + visible: false |
1784 | + } |
1785 | + |
1786 | + EdgeDragArea { |
1787 | + id: spreadDragArea |
1788 | + direction: Direction.Leftwards |
1789 | + enabled: ApplicationManager.count > 1 && spreadView.phase != 2 |
1790 | + |
1791 | + anchors { top: parent.top; right: parent.right; bottom: parent.bottom } |
1792 | + width: root.dragAreaWidth |
1793 | + |
1794 | + // Sitting at the right edge of the screen, this EdgeDragArea directly controls the spreadView when |
1795 | + // attachedToView is true. When the finger movement passes positionMarker3 we detach it from the |
1796 | + // spreadView and make the spreadView snap to positionMarker4. |
1797 | + property bool attachedToView: true |
1798 | + |
1799 | + property var gesturePoints: new Array() |
1800 | + |
1801 | + onTouchXChanged: { |
1802 | + if (!dragging && !priv.waitingForScreenshot) { |
1803 | + // Initial touch. Let's update the screenshot and reset the spreadView to the starting position. |
1804 | + priv.requestNewScreenshot(); |
1805 | + spreadView.phase = 0; |
1806 | + spreadView.contentX = -spreadView.shift; |
1807 | + } |
1808 | + if (dragging && attachedToView) { |
1809 | + // Gesture recognized. Let's move the spreadView with the finger |
1810 | + spreadView.contentX = -touchX - spreadView.shift; |
1811 | + } |
1812 | + if (attachedToView && spreadView.shiftedContentX >= spreadView.width * spreadView.positionMarker3) { |
1813 | + // We passed positionMarker3. Detach from spreadView and snap it. |
1814 | + attachedToView = false; |
1815 | + spreadView.snap(); |
1816 | + } |
1817 | + gesturePoints.push(touchX); |
1818 | + } |
1819 | + |
1820 | + onStatusChanged: { |
1821 | + if (status == DirectionalDragArea.Recognized) { |
1822 | + attachedToView = true; |
1823 | + } |
1824 | + } |
1825 | + |
1826 | + onDraggingChanged: { |
1827 | + if (dragging) { |
1828 | + // Gesture recognized. Start recording this gesture |
1829 | + gesturePoints = []; |
1830 | + return; |
1831 | + } |
1832 | + |
1833 | + // Ok. The user released. Find out if it was a one-way movement. |
1834 | + var oneWayFlick = true; |
1835 | + var smallestX = spreadDragArea.width; |
1836 | + for (var i = 0; i < gesturePoints.length; i++) { |
1837 | + if (gesturePoints[i] >= smallestX) { |
1838 | + oneWayFlick = false; |
1839 | + break; |
1840 | + } |
1841 | + smallestX = gesturePoints[i]; |
1842 | + } |
1843 | + gesturePoints = []; |
1844 | + |
1845 | + if (oneWayFlick && spreadView.shiftedContentX > units.gu(2) && |
1846 | + spreadView.shiftedContentX < spreadView.positionMarker1 * spreadView.width) { |
1847 | + // If it was a short one-way movement, do the Alt+Tab switch |
1848 | + // no matter if we didn't cross positionMarker1 yet. |
1849 | + spreadView.snapTo(1); |
1850 | + } else if (!dragging && attachedToView) { |
1851 | + // otherwise snap to the closest snap position we can find |
1852 | + // (might be back to start, to app 1 or to spread) |
1853 | + spreadView.snap(); |
1854 | + } |
1855 | + } |
1856 | + } |
1857 | + |
1858 | + Rectangle { |
1859 | + id: coverFlipBackground |
1860 | + anchors.fill: parent |
1861 | + color: "black" |
1862 | + visible: spreadView.visible |
1863 | + } |
1864 | + |
1865 | + InputFilterArea { |
1866 | + anchors.fill: root |
1867 | + blockInput: spreadView.visible |
1868 | + } |
1869 | + |
1870 | + Flickable { |
1871 | + id: spreadView |
1872 | + objectName: "spreadView" |
1873 | + anchors.fill: parent |
1874 | + visible: spreadDragArea.status == DirectionalDragArea.Recognized || phase > 1 || snapAnimation.running |
1875 | + contentWidth: spreadRow.width - shift |
1876 | + contentX: -shift |
1877 | + |
1878 | + // The flickable needs to fill the screen in order to get touch events all over. |
1879 | + // However, we don't want to the user to be able to scroll back all the way. For |
1880 | + // that, the beginning of the gesture starts with a negative value for contentX |
1881 | + // so the flickable wants to pull it into the view already. "shift" tunes the |
1882 | + // distance where to "lock" the content. |
1883 | + property real shift: width / 2 |
1884 | + property real shiftedContentX: contentX + shift |
1885 | + |
1886 | + property int tileDistance: width / 4 |
1887 | + |
1888 | + // Those markers mark the various positions in the spread (ratio to screen width from right to left): |
1889 | + // 0 - 1: following finger, snap back to the beginning on release |
1890 | + property real positionMarker1: 0.3 |
1891 | + // 1 - 2: curved snapping movement, snap to app 1 on release |
1892 | + property real positionMarker2: 0.45 |
1893 | + // 2 - 3: movement follows finger, snaps back to app 1 on release |
1894 | + property real positionMarker3: 0.6 |
1895 | + // passing 3, we detach movement from the finger and snap to 4 |
1896 | + property real positionMarker4: 0.9 |
1897 | + |
1898 | + // This is where the first app snaps to when bringing it in from the right edge. |
1899 | + property real snapPosition: 0.75 |
1900 | + |
1901 | + // Phase of the animation: |
1902 | + // 0: Starting from right edge, a new app (index 1) comes in from the right |
1903 | + // 1: The app has reached the first snap position. |
1904 | + // 2: The list is dragged further and snaps into the spread view when entering phase 2 |
1905 | + property int phase: 0 |
1906 | + |
1907 | + property int selectedIndex: -1 |
1908 | + |
1909 | + onShiftedContentXChanged: { |
1910 | + switch (phase) { |
1911 | + case 0: |
1912 | + if (shiftedContentX > width * positionMarker2) { |
1913 | + phase = 1; |
1914 | + } |
1915 | + break; |
1916 | + case 1: |
1917 | + if (shiftedContentX < width * positionMarker2) { |
1918 | + phase = 0; |
1919 | + } else if (shiftedContentX >= width * positionMarker4) { |
1920 | + phase = 2; |
1921 | + } |
1922 | + break; |
1923 | + } |
1924 | + } |
1925 | + |
1926 | + function snap() { |
1927 | + if (shiftedContentX < positionMarker1 * width) { |
1928 | + snapAnimation.targetContentX = -shift; |
1929 | + snapAnimation.start(); |
1930 | + } else if (shiftedContentX < positionMarker2 * width) { |
1931 | + snapTo(1) |
1932 | + } else if (shiftedContentX < positionMarker3 * width) { |
1933 | + snapTo(1) |
1934 | + } else if (phase < 2){ |
1935 | + // Add 1 pixel to make sure we definitely hit positionMarker4 even with rounding errors of the animation. |
1936 | + snapAnimation.targetContentX = width * positionMarker4 + 1 - shift; |
1937 | + snapAnimation.start(); |
1938 | + } |
1939 | + } |
1940 | + function snapTo(index) { |
1941 | + spreadView.selectedIndex = index; |
1942 | + root.fullscreen = ApplicationManager.get(index).fullscreen; |
1943 | + snapAnimation.targetContentX = -shift; |
1944 | + snapAnimation.start(); |
1945 | + } |
1946 | + |
1947 | + SequentialAnimation { |
1948 | + id: snapAnimation |
1949 | + property int targetContentX: -spreadView.shift |
1950 | + |
1951 | + UbuntuNumberAnimation { |
1952 | + target: spreadView |
1953 | + property: "contentX" |
1954 | + to: snapAnimation.targetContentX |
1955 | + duration: UbuntuAnimation.FastDuration |
1956 | + } |
1957 | + |
1958 | + ScriptAction { |
1959 | + script: { |
1960 | + if (spreadView.selectedIndex >= 0) { |
1961 | + ApplicationManager.focusApplication(ApplicationManager.get(spreadView.selectedIndex).appId); |
1962 | + spreadView.selectedIndex = -1 |
1963 | + spreadView.phase = 0; |
1964 | + spreadView.contentX = -spreadView.shift; |
1965 | + } |
1966 | + } |
1967 | + } |
1968 | + } |
1969 | + |
1970 | + Item { |
1971 | + id: spreadRow |
1972 | + // This width controls how much the spread can be flicked left/right. It's composed of: |
1973 | + // tileDistance * app count (with a minimum of 3 apps, in order to also allow moving 1 and 2 apps a bit) |
1974 | + // + some constant value (still scales with the screen width) which looks good and somewhat fills the screen |
1975 | + width: Math.max(3, ApplicationManager.count) * spreadView.tileDistance + (spreadView.width - spreadView.tileDistance) * 1.5 |
1976 | + |
1977 | + x: spreadView.contentX |
1978 | + |
1979 | + Repeater { |
1980 | + id: spreadRepeater |
1981 | + model: ApplicationManager |
1982 | + delegate: TransformedSpreadDelegate { |
1983 | + id: appDelegate |
1984 | + objectName: "appDelegate" + index |
1985 | + startAngle: 45 |
1986 | + endAngle: 5 |
1987 | + startScale: 1.1 |
1988 | + endScale: 0.7 |
1989 | + startDistance: spreadView.tileDistance |
1990 | + endDistance: units.gu(.5) |
1991 | + width: spreadView.width |
1992 | + height: spreadView.height |
1993 | + selected: spreadView.selectedIndex == index |
1994 | + otherSelected: spreadView.selectedIndex >= 0 && !selected |
1995 | + |
1996 | + z: index |
1997 | + x: index == 0 ? 0 : spreadView.width + (index - 1) * spreadView.tileDistance |
1998 | + |
1999 | + // Each tile has a different progress value running from 0 to 1. |
2000 | + // A progress value of 0 means the tile is at the right edge. 1 means the tile has reched the left edge. |
2001 | + progress: { |
2002 | + var tileProgress = (spreadView.shiftedContentX - index * spreadView.tileDistance) / spreadView.width; |
2003 | + // Tile 1 needs to move directly from the beginning... |
2004 | + if (index == 1 && spreadView.phase < 2) { |
2005 | + tileProgress += spreadView.tileDistance / spreadView.width; |
2006 | + } |
2007 | + return tileProgress; |
2008 | + } |
2009 | + |
2010 | + // This mostly is the same as progress, just adds the snapping to phase 1 for tiles 0 and 1 |
2011 | + animatedProgress: { |
2012 | + if (spreadView.phase == 0 && index < 2) { |
2013 | + if (progress < spreadView.positionMarker1) { |
2014 | + return progress; |
2015 | + } else if (progress < spreadView.positionMarker1 + snappingCurve.period){ |
2016 | + return spreadView.positionMarker1 + snappingCurve.value * 3; |
2017 | + } else { |
2018 | + return spreadView.positionMarker2; |
2019 | + } |
2020 | + } |
2021 | + return progress; |
2022 | + } |
2023 | + |
2024 | + EasingCurve { |
2025 | + id: snappingCurve |
2026 | + type: EasingCurve.OutQuad |
2027 | + period: 0.05 |
2028 | + progress: appDelegate.progress - spreadView.positionMarker1 |
2029 | + } |
2030 | + |
2031 | + onClicked: { |
2032 | + if (spreadView.phase == 2) { |
2033 | + if (ApplicationManager.focusedApplicationId == ApplicationManager.get(index).appId) { |
2034 | + spreadView.snapTo(index); |
2035 | + } else { |
2036 | + ApplicationManager.requestFocusApplication(ApplicationManager.get(index).appId); |
2037 | + } |
2038 | + } |
2039 | + } |
2040 | + } |
2041 | + } |
2042 | + } |
2043 | + } |
2044 | +} |
2045 | |
2046 | === renamed file 'qml/SideStage/SidestageHandle.qml' => 'qml/Stages/SidestageHandle.qml' |
2047 | === added file 'qml/Stages/SpreadDelegate.qml' |
2048 | --- qml/Stages/SpreadDelegate.qml 1970-01-01 00:00:00 +0000 |
2049 | +++ qml/Stages/SpreadDelegate.qml 2014-03-25 15:08:15 +0000 |
2050 | @@ -0,0 +1,55 @@ |
2051 | +/* |
2052 | + * Copyright 2014 Canonical Ltd. |
2053 | + * |
2054 | + * This program is free software; you can redistribute it and/or modify |
2055 | + * it under the terms of the GNU Lesser General Public License as published by |
2056 | + * the Free Software Foundation; version 3. |
2057 | + * |
2058 | + * This program is distributed in the hope that it will be useful, |
2059 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2060 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2061 | + * GNU Lesser General Public License for more details. |
2062 | + * |
2063 | + * You should have received a copy of the GNU Lesser General Public License |
2064 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2065 | + * |
2066 | + * Authors: Michael Zanetti <michael.zanetti@canonical.com> |
2067 | +*/ |
2068 | + |
2069 | +import QtQuick 2.0 |
2070 | + |
2071 | +Item { |
2072 | + id: root |
2073 | + |
2074 | + signal clicked() |
2075 | + |
2076 | + property real topMarginProgress |
2077 | + |
2078 | + QtObject { |
2079 | + id: priv |
2080 | + property real heightDifference: root.height - appImage.implicitHeight |
2081 | + } |
2082 | + |
2083 | + Image { |
2084 | + id: dropShadow |
2085 | + anchors.fill: appImage |
2086 | + anchors.margins: -units.gu(2) |
2087 | + source: "graphics/dropshadow.png" |
2088 | + opacity: .4 |
2089 | + } |
2090 | + Image { |
2091 | + id: appImage |
2092 | + anchors { |
2093 | + left: parent.left; |
2094 | + bottom: parent.bottom; |
2095 | + top: parent.top; |
2096 | + topMargin: priv.heightDifference * Math.max(0, 1 - root.topMarginProgress) |
2097 | + } |
2098 | + source: model.screenshot |
2099 | + antialiasing: true |
2100 | + } |
2101 | + MouseArea { |
2102 | + anchors.fill: appImage |
2103 | + onClicked: root.clicked() |
2104 | + } |
2105 | +} |
2106 | |
2107 | === added file 'qml/Stages/StageWithSideStage.qml' |
2108 | --- qml/Stages/StageWithSideStage.qml 1970-01-01 00:00:00 +0000 |
2109 | +++ qml/Stages/StageWithSideStage.qml 2014-03-25 15:08:15 +0000 |
2110 | @@ -0,0 +1,405 @@ |
2111 | +/* |
2112 | + * Copyright (C) 2014 Canonical, Ltd. |
2113 | + * |
2114 | + * This program is free software; you can redistribute it and/or modify |
2115 | + * it under the terms of the GNU General Public License as published by |
2116 | + * the Free Software Foundation; version 3. |
2117 | + * |
2118 | + * This program is distributed in the hope that it will be useful, |
2119 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2120 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2121 | + * GNU General Public License for more details. |
2122 | + * |
2123 | + * You should have received a copy of the GNU General Public License |
2124 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2125 | + */ |
2126 | + |
2127 | +import QtQuick 2.0 |
2128 | +import Ubuntu.Components 0.1 |
2129 | +import "../Components" |
2130 | +import Unity.Application 0.1 |
2131 | +import Ubuntu.Gestures 0.1 |
2132 | + |
2133 | +Item { |
2134 | + id: root |
2135 | + objectName: "stages" |
2136 | + anchors.fill: parent |
2137 | + |
2138 | + // Controls to be set from outside |
2139 | + property bool shown: false |
2140 | + property bool moving: false |
2141 | + property int dragAreaWidth |
2142 | + |
2143 | + // State information propagated to the outside |
2144 | + readonly property bool painting: mainStageImage.visible || sideStageImage.visible || sideStageSnapAnimation.running |
2145 | + property bool fullscreen: priv.focusedApplication ? priv.focusedApplication.fullscreen : false |
2146 | + property bool overlayMode: (sideStageImage.shown && priv.mainStageAppId.length == 0) || priv.overlayOverride |
2147 | + || (priv.mainStageAppId.length == 0 && sideStageSnapAnimation.running) |
2148 | + |
2149 | + readonly property int overlayWidth: priv.overlayOverride ? 0 : priv.sideStageWidth |
2150 | + |
2151 | + onShownChanged: { |
2152 | + if (!shown) { |
2153 | + priv.mainStageAppId = ""; |
2154 | + } |
2155 | + } |
2156 | + |
2157 | + onMovingChanged: { |
2158 | + if (moving) { |
2159 | + if (!priv.mainStageAppId && !priv.sideStageAppId) { |
2160 | + // Pulling in from the right, make the last used (topmost) app visible |
2161 | + var application = ApplicationManager.get(0); |
2162 | + if (application.stage == ApplicationInfoInterface.SideStage) { |
2163 | + sideStageImage.application = application; |
2164 | + sideStageImage.x = root.width - sideStageImage.width |
2165 | + sideStageImage.visible = true; |
2166 | + } else { |
2167 | + mainStageImage.application = application; |
2168 | + mainStageImage.visible = true; |
2169 | + } |
2170 | + } else { |
2171 | + priv.requestNewScreenshot(ApplicationInfoInterface.MainStage) |
2172 | + if (priv.focusedApplicationId == priv.sideStageAppId) { |
2173 | + priv.requestNewScreenshot(ApplicationInfoInterface.SideStage) |
2174 | + } |
2175 | + } |
2176 | + } else { |
2177 | + mainStageImage.visible = false; |
2178 | + sideStageImage.visible = false; |
2179 | + } |
2180 | + } |
2181 | + |
2182 | + QtObject { |
2183 | + id: priv |
2184 | + |
2185 | + property int sideStageWidth: units.gu(40) |
2186 | + |
2187 | + |
2188 | + property string sideStageAppId |
2189 | + property string mainStageAppId |
2190 | + |
2191 | + |
2192 | + property var sideStageApp: ApplicationManager.findApplication(sideStageAppId) |
2193 | + property var mainStageApp: ApplicationManager.findApplication(mainStageAppId) |
2194 | + |
2195 | + property string sideStageScreenshot: sideStageApp ? sideStageApp.screenshot : "" |
2196 | + property string mainStageScreenshot: mainStageApp ? mainStageApp.screenshot : "" |
2197 | + |
2198 | + property string focusedApplicationId: ApplicationManager.focusedApplicationId |
2199 | + property var focusedApplication: ApplicationManager.findApplication(focusedApplicationId) |
2200 | + property url focusedScreenshot: focusedApplication ? focusedApplication.screenshot : "" |
2201 | + |
2202 | + property bool waitingForMainScreenshot: false |
2203 | + property bool waitingForSideScreenshot: false |
2204 | + property bool waitingForScreenshots: waitingForMainScreenshot || waitingForSideScreenshot |
2205 | + |
2206 | + property string startingAppId: "" |
2207 | + |
2208 | + // Keep overlayMode even if there is no focused app (to allow pulling in the sidestage from the right) |
2209 | + property bool overlayOverride: false |
2210 | + |
2211 | + onFocusedApplicationChanged: { |
2212 | + if (focusedApplication) { |
2213 | + if (focusedApplication.stage == ApplicationInfoInterface.MainStage) { |
2214 | + mainStageAppId = focusedApplicationId; |
2215 | + priv.overlayOverride = false; |
2216 | + if (priv.startingAppId == focusedApplicationId && sideStageImage.shown) { |
2217 | + // There was already a sidestage app on top. bring it back! |
2218 | + ApplicationManager.focusApplication(priv.sideStageAppId) |
2219 | + priv.startingAppId = ""; |
2220 | + } |
2221 | + } else if (focusedApplication.stage == ApplicationInfoInterface.SideStage) { |
2222 | + sideStageAppId = focusedApplicationId; |
2223 | + if (priv.startingAppId == focusedApplicationId && !sideStageImage.shown) { |
2224 | + sideStageImage.snapToApp(focusedApplication); |
2225 | + priv.startingAppId = ""; |
2226 | + } |
2227 | + } |
2228 | + } |
2229 | + } |
2230 | + |
2231 | + onMainStageScreenshotChanged: { |
2232 | + waitingForMainScreenshot = false; |
2233 | + } |
2234 | + |
2235 | + onSideStageScreenshotChanged: { |
2236 | + waitingForSideScreenshot = false; |
2237 | + } |
2238 | + |
2239 | + onFocusedScreenshotChanged: { |
2240 | + waitingForSideScreenshot = false; |
2241 | + } |
2242 | + |
2243 | + onWaitingForScreenshotsChanged: { |
2244 | + if (waitingForScreenshots) { |
2245 | + return; |
2246 | + } |
2247 | + |
2248 | + if (root.moving) { |
2249 | + if (mainStageAppId) { |
2250 | + mainStageImage.application = mainStageApp |
2251 | + mainStageImage.visible = true; |
2252 | + } |
2253 | + if (sideStageAppId && focusedApplicationId == sideStageAppId) { |
2254 | + sideStageImage.application = sideStageApp; |
2255 | + sideStageImage.x = root.width - sideStageImage.width |
2256 | + sideStageImage.visible = true; |
2257 | + } |
2258 | + } |
2259 | + if (sideStageHandleMouseArea.pressed) { |
2260 | + if (sideStageAppId) { |
2261 | + sideStageImage.application = sideStageApp; |
2262 | + sideStageImage.x = root.width - sideStageImage.width |
2263 | + sideStageImage.visible = true; |
2264 | + } |
2265 | + if (mainStageAppId) { |
2266 | + mainStageImage.application = mainStageApp |
2267 | + mainStageImage.visible = true; |
2268 | + } |
2269 | + } |
2270 | + } |
2271 | + |
2272 | + function requestNewScreenshot(stage) { |
2273 | + if (stage == ApplicationInfoInterface.MainStage && mainStageAppId) { |
2274 | + waitingForMainScreenshot = true; |
2275 | + ApplicationManager.updateScreenshot(mainStageAppId); |
2276 | + } else if (stage == ApplicationInfoInterface.SideStage && sideStageAppId) { |
2277 | + waitingForSideScreenshot = true; |
2278 | + ApplicationManager.updateScreenshot(sideStageAppId); |
2279 | + } |
2280 | + } |
2281 | + |
2282 | + } |
2283 | + // FIXME: the signal connection seems to get lost with the fake application manager. |
2284 | + Connections { |
2285 | + target: priv.sideStageApp |
2286 | + onScreenshotChanged: priv.sideStageScreenshot = priv.sideStageApp.screenshot |
2287 | + } |
2288 | + Connections { |
2289 | + target: priv.mainStageApp |
2290 | + onScreenshotChanged: priv.mainStageScreenshot = priv.mainStageApp.screenshot |
2291 | + } |
2292 | + |
2293 | + Connections { |
2294 | + target: ApplicationManager |
2295 | + |
2296 | + onApplicationAdded: { |
2297 | + priv.startingAppId = appId; |
2298 | + splashScreenTimer.start(); |
2299 | + var application = ApplicationManager.findApplication(appId) |
2300 | + if (application.stage == ApplicationInfoInterface.SideStage) { |
2301 | + sideStageSplash.visible = true; |
2302 | + } else if (application.stage == ApplicationInfoInterface.MainStage) { |
2303 | + mainStageSplash.visible = true; |
2304 | + } |
2305 | + } |
2306 | + |
2307 | + onFocusRequested: { |
2308 | + var application = ApplicationManager.findApplication(appId) |
2309 | + if (application.stage == ApplicationInfoInterface.SideStage) { |
2310 | + if (!root.shown) { |
2311 | + priv.mainStageAppId = ""; |
2312 | + mainStageImage.application = null |
2313 | + } |
2314 | + if (sideStageImage.shown) { |
2315 | + sideStageImage.switchTo(application); |
2316 | + if (priv.mainStageAppId) { |
2317 | + mainStageImage.application = priv.mainStageApp; |
2318 | + mainStageImage.visible = true; |
2319 | + } |
2320 | + } else { |
2321 | + sideStageImage.application = application; |
2322 | + sideStageImage.snapToApp(application); |
2323 | + } |
2324 | + } else if (application.stage == ApplicationInfoInterface.MainStage) { |
2325 | + if (root.shown) { |
2326 | + if (sideStageImage.shown) { |
2327 | + sideStageImage.application = priv.sideStageApp; |
2328 | + sideStageImage.visible = true; |
2329 | + } |
2330 | + priv.mainStageAppId = application.appId; |
2331 | + mainStageImage.switchTo(application) |
2332 | + ApplicationManager.focusApplication(appId) |
2333 | + if (sideStageImage.shown) { |
2334 | + // There was already a focused SS app. Bring it back |
2335 | + ApplicationManager.focusApplication(priv.sideStageAppId) |
2336 | + } |
2337 | + } else { |
2338 | + if (sideStageImage.shown) { |
2339 | + sideStageImage.visible = false; |
2340 | + sideStageImage.x = root.width; |
2341 | + } |
2342 | + |
2343 | + mainStageImage.application = application; |
2344 | + ApplicationManager.focusApplication(appId) |
2345 | + } |
2346 | + } |
2347 | + } |
2348 | + |
2349 | + onApplicationRemoved: { |
2350 | + if (priv.mainStageAppId == appId) { |
2351 | + priv.mainStageAppId = ""; |
2352 | + } |
2353 | + if (priv.sideStageAppId == appId) { |
2354 | + priv.sideStageAppId = ""; |
2355 | + } |
2356 | + if (priv.sideStageAppId.length == 0) { |
2357 | + sideStageImage.shown = false; |
2358 | + priv.overlayOverride = false; |
2359 | + } |
2360 | + } |
2361 | + |
2362 | + } |
2363 | + |
2364 | + Timer { |
2365 | + id: splashScreenTimer |
2366 | + // FIXME: apart from removing this completely in the future and make the app surface paint |
2367 | + // meaningful stuff, also check for colin's stuff to land so we can shape 1.4 secs away from here |
2368 | + // https://code.launchpad.net/~cjwatson/upstart-app-launch/libclick-manifest/+merge/210520 |
2369 | + // https://code.launchpad.net/~cjwatson/upstart-app-launch/libclick-pkgdir/+merge/209909 |
2370 | + interval: 1700 |
2371 | + repeat: false |
2372 | + onTriggered: { |
2373 | + mainStageSplash.visible = false; |
2374 | + sideStageSplash.visible = false; |
2375 | + } |
2376 | + } |
2377 | + |
2378 | + SwitchingApplicationImage { |
2379 | + id: mainStageImage |
2380 | + anchors.bottom: parent.bottom |
2381 | + width: parent.width |
2382 | + visible: false |
2383 | + |
2384 | + onSwitched: { |
2385 | + sideStageImage.visible = false; |
2386 | + } |
2387 | + } |
2388 | + |
2389 | + Rectangle { |
2390 | + id: mainStageSplash |
2391 | + anchors.fill: root |
2392 | + anchors.rightMargin: root.width - sideStageImage.x |
2393 | + color: "white" |
2394 | + } |
2395 | + |
2396 | + SidestageHandle { |
2397 | + id: sideStageHandle |
2398 | + anchors { top: parent.top; right: sideStageImage.left; bottom: parent.bottom } |
2399 | + width: root.dragAreaWidth |
2400 | + visible: root.shown && priv.sideStageAppId && sideStageImage.x < root.width |
2401 | + |
2402 | + } |
2403 | + MouseArea { |
2404 | + id: sideStageHandleMouseArea |
2405 | + anchors { top: parent.top; right: parent.right; bottom: parent.bottom; rightMargin: sideStageImage.shown ? sideStageImage.width : 0} |
2406 | + width: root.dragAreaWidth |
2407 | + visible: priv.sideStageAppId |
2408 | + |
2409 | + property var dragPoints: new Array() |
2410 | + |
2411 | + onPressed: { |
2412 | + priv.requestNewScreenshot(ApplicationInfoInterface.SideStage) |
2413 | + if (priv.mainStageAppId) { |
2414 | + priv.requestNewScreenshot(ApplicationInfoInterface.MainStage) |
2415 | + } |
2416 | + } |
2417 | + |
2418 | + onMouseXChanged: { |
2419 | + dragPoints.push(mouseX) |
2420 | + |
2421 | + var dragPoint = root.width + mouseX; |
2422 | + if (sideStageImage.shown) { |
2423 | + dragPoint -= sideStageImage.width |
2424 | + } |
2425 | + sideStageImage.x = Math.max(root.width - sideStageImage.width, dragPoint) |
2426 | + } |
2427 | + |
2428 | + onReleased: { |
2429 | + var distance = 0; |
2430 | + var lastX = dragPoints[0]; |
2431 | + var oneWayFlick = true; |
2432 | + for (var i = 0; i < dragPoints.length; ++i) { |
2433 | + if (dragPoints[i] < lastX) { |
2434 | + oneWayFlick = false; |
2435 | + } |
2436 | + distance += dragPoints[i] - lastX; |
2437 | + lastX = dragPoints[i]; |
2438 | + } |
2439 | + dragPoints = []; |
2440 | + |
2441 | + if (oneWayFlick || distance > sideStageImage.width / 2) { |
2442 | + sideStageImage.snapTo(root.width) |
2443 | + } else { |
2444 | + sideStageImage.snapToApp(priv.sideStageApp) |
2445 | + } |
2446 | + } |
2447 | + } |
2448 | + |
2449 | + SwitchingApplicationImage { |
2450 | + id: sideStageImage |
2451 | + width: priv.sideStageWidth |
2452 | + height: root.height |
2453 | + x: root.width |
2454 | + anchors.bottom: parent.bottom |
2455 | + visible: true |
2456 | + property bool shown: false |
2457 | + |
2458 | + onSwitched: { |
2459 | + mainStageImage.visible = false; |
2460 | + ApplicationManager.focusApplication(application.appId) |
2461 | + } |
2462 | + |
2463 | + function snapTo(targetX) { |
2464 | + sideStageSnapAnimation.targetX = targetX |
2465 | + sideStageImage.visible = true; |
2466 | + if (priv.mainStageAppId) { |
2467 | + mainStageImage.application = priv.mainStageApp |
2468 | + mainStageImage.visible = true; |
2469 | + } |
2470 | + sideStageSnapAnimation.start(); |
2471 | + } |
2472 | + |
2473 | + function snapToApp(application) { |
2474 | + sideStageImage.application = application |
2475 | + sideStageSnapAnimation.snapToId = application.appId; |
2476 | + snapTo(root.width - sideStageImage.width); |
2477 | + } |
2478 | + |
2479 | + SequentialAnimation { |
2480 | + id: sideStageSnapAnimation |
2481 | + property int targetX: root.width |
2482 | + property string snapToId |
2483 | + |
2484 | + UbuntuNumberAnimation { target: sideStageImage; property: "x"; to: sideStageSnapAnimation.targetX; duration: UbuntuAnimation.SlowDuration } |
2485 | + ScriptAction { |
2486 | + script: { |
2487 | + if (sideStageSnapAnimation.targetX == root.width) { |
2488 | + if (priv.mainStageAppId) { |
2489 | + ApplicationManager.focusApplication(priv.mainStageAppId) |
2490 | + } else { |
2491 | + priv.overlayOverride = true; |
2492 | + ApplicationManager.unfocusCurrentApplication(); |
2493 | + } |
2494 | + sideStageImage.shown = false; |
2495 | + } |
2496 | + if (sideStageSnapAnimation.snapToId) { |
2497 | + ApplicationManager.focusApplication(sideStageSnapAnimation.snapToId) |
2498 | + sideStageSnapAnimation.snapToId = ""; |
2499 | + sideStageImage.shown = true; |
2500 | + priv.overlayOverride = false; |
2501 | + } |
2502 | + sideStageImage.visible = false; |
2503 | + mainStageImage.visible = false; |
2504 | + } |
2505 | + } |
2506 | + } |
2507 | + } |
2508 | + |
2509 | + Rectangle { |
2510 | + id: sideStageSplash |
2511 | + anchors.fill: parent |
2512 | + anchors.leftMargin: sideStageImage.x |
2513 | + color: "white" |
2514 | + } |
2515 | +} |
2516 | |
2517 | === added file 'qml/Stages/SwitchingApplicationImage.qml' |
2518 | --- qml/Stages/SwitchingApplicationImage.qml 1970-01-01 00:00:00 +0000 |
2519 | +++ qml/Stages/SwitchingApplicationImage.qml 2014-03-25 15:08:15 +0000 |
2520 | @@ -0,0 +1,81 @@ |
2521 | +/* |
2522 | + * Copyright 2014 Canonical Ltd. |
2523 | + * |
2524 | + * This program is free software; you can redistribute it and/or modify |
2525 | + * it under the terms of the GNU Lesser General Public License as published by |
2526 | + * the Free Software Foundation; version 3. |
2527 | + * |
2528 | + * This program is distributed in the hope that it will be useful, |
2529 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2530 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2531 | + * GNU Lesser General Public License for more details. |
2532 | + * |
2533 | + * You should have received a copy of the GNU Lesser General Public License |
2534 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2535 | + * |
2536 | + * Authors: Michael Zanetti <michael.zanetti@canonical.com> |
2537 | +*/ |
2538 | + |
2539 | +import QtQuick 2.0 |
2540 | +import Ubuntu.Components 0.1 |
2541 | + |
2542 | +Rectangle { |
2543 | + id: root |
2544 | + implicitHeight: image.implicitHeight |
2545 | + implicitWidth: image.implicitWidth |
2546 | + color: "black" |
2547 | + |
2548 | + property var application |
2549 | + |
2550 | + signal switched() |
2551 | + |
2552 | + function switchTo(application) { |
2553 | + if (root.application == application) { |
2554 | + root.switched(); |
2555 | + return; |
2556 | + } |
2557 | + |
2558 | + priv.newApplication = application |
2559 | + root.visible = true; |
2560 | + switchToAnimation.start() |
2561 | + } |
2562 | + |
2563 | + QtObject { |
2564 | + id: priv |
2565 | + property var newApplication |
2566 | + } |
2567 | + |
2568 | + Image { |
2569 | + id: newImage |
2570 | + anchors.bottom: parent.bottom |
2571 | + width: root.width |
2572 | + source: priv.newApplication ? priv.newApplication.screenshot : "" |
2573 | + } |
2574 | + |
2575 | + Image { |
2576 | + id: image |
2577 | + visible: true |
2578 | + source: root.application ? root.application.screenshot : "" |
2579 | + width: root.width |
2580 | + height: sourceSize.height |
2581 | + anchors.bottom: parent.bottom |
2582 | + |
2583 | + } |
2584 | + |
2585 | + SequentialAnimation { |
2586 | + id: switchToAnimation |
2587 | + ParallelAnimation { |
2588 | + UbuntuNumberAnimation { target: image; property: "x"; from: 0; to: root.width; duration: UbuntuAnimation.SlowDuration } |
2589 | + UbuntuNumberAnimation { target: newImage; property: "scale"; from: 0.7; to: 1; duration: UbuntuAnimation.SlowDuration } |
2590 | + } |
2591 | + ScriptAction { |
2592 | + script: { |
2593 | + image.x = 0 |
2594 | + root.application = priv.newApplication |
2595 | + root.visible = false; |
2596 | + priv.newApplication = null |
2597 | + root.switched(); |
2598 | + } |
2599 | + } |
2600 | + } |
2601 | +} |
2602 | |
2603 | === added file 'qml/Stages/TransformedSpreadDelegate.qml' |
2604 | --- qml/Stages/TransformedSpreadDelegate.qml 1970-01-01 00:00:00 +0000 |
2605 | +++ qml/Stages/TransformedSpreadDelegate.qml 2014-03-25 15:08:15 +0000 |
2606 | @@ -0,0 +1,327 @@ |
2607 | +/* |
2608 | + * Copyright 2014 Canonical Ltd. |
2609 | + * |
2610 | + * This program is free software; you can redistribute it and/or modify |
2611 | + * it under the terms of the GNU Lesser General Public License as published by |
2612 | + * the Free Software Foundation; version 3. |
2613 | + * |
2614 | + * This program is distributed in the hope that it will be useful, |
2615 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2616 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2617 | + * GNU Lesser General Public License for more details. |
2618 | + * |
2619 | + * You should have received a copy of the GNU Lesser General Public License |
2620 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2621 | + * |
2622 | + * Authors: Michael Zanetti <michael.zanetti@canonical.com> |
2623 | +*/ |
2624 | + |
2625 | +import QtQuick 2.0 |
2626 | +import Utils 0.1 |
2627 | +import Ubuntu.Components 0.1 |
2628 | + |
2629 | +SpreadDelegate { |
2630 | + id: root |
2631 | + |
2632 | + property bool selected: false |
2633 | + property bool otherSelected: false |
2634 | + |
2635 | + // The progress animates the tiles. A value > 0 makes it appear from the right edge. At 1 it reaches the end position. |
2636 | + property real progress: 0 |
2637 | + // This is required to snap tile 1 during phase 1 and 2. |
2638 | + property real animatedProgress: 0 |
2639 | + |
2640 | + property real startAngle: 0 |
2641 | + property real endAngle: 0 |
2642 | + |
2643 | + property real startScale: 1 |
2644 | + property real endScale: 1 |
2645 | + |
2646 | + // Specific to just one tile |
2647 | + property real tile1StartScale: startScale + .4 |
2648 | + property real tile0SnapAngle: 10 |
2649 | + |
2650 | + property real startDistance: units.gu(5) |
2651 | + property real endDistance: units.gu(.5) |
2652 | + |
2653 | + onSelectedChanged: { |
2654 | + if (selected) { |
2655 | + priv.snapshot(); |
2656 | + } |
2657 | + priv.isSelected = selected; |
2658 | + } |
2659 | + |
2660 | + onOtherSelectedChanged: { |
2661 | + if (otherSelected) { |
2662 | + priv.snapshot(); |
2663 | + } |
2664 | + priv.otherSelected = otherSelected; |
2665 | + } |
2666 | + |
2667 | + Connections { |
2668 | + target: spreadView |
2669 | + onPhaseChanged: { |
2670 | + if (spreadView.phase == 1) { |
2671 | + if (index == 0) { |
2672 | + priv.phase2startTranslate = priv.easingAnimation(0, spreadView.positionMarker4, 0, -spreadView.width, spreadView.positionMarker4) + spreadView.width; |
2673 | + priv.phase2startAngle = priv.easingAnimation(0, spreadView.positionMarker4, root.startAngle, root.endAngle, spreadView.positionMarker4); |
2674 | + priv.phase2startScale = priv.easingAnimation(0, spreadView.positionMarker4, root.startScale, root.endScale, spreadView.positionMarker4); |
2675 | + priv.phase2startTopMarginProgress = priv.easingAnimation(0, 1, 0, 1, spreadView.positionMarker4); |
2676 | + } else if (index == 1) { |
2677 | + // find where the main easing for Tile 1 would be when reaching phase 2 |
2678 | + var phase2Progress = spreadView.positionMarker4 - spreadView.tileDistance / spreadView.width; |
2679 | + priv.phase2startTranslate = priv.easingAnimation(0, phase2Progress, 0, -spreadView.width + root.endDistance, phase2Progress); |
2680 | + priv.phase2startAngle = priv.easingAnimation(0, phase2Progress, root.startAngle, root.endAngle, phase2Progress); |
2681 | + priv.phase2startScale = priv.easingAnimation(0, phase2Progress, root.startScale, root.endScale, phase2Progress); |
2682 | + priv.phase2startTopMarginProgress = priv.easingAnimation(0, 1, 0, spreadView.positionMarker4, phase2Progress); |
2683 | + } |
2684 | + } |
2685 | + } |
2686 | + } |
2687 | + |
2688 | + QtObject { |
2689 | + id: priv |
2690 | + property bool isSelected: false |
2691 | + property bool otherSelected: false |
2692 | + property real selectedProgress |
2693 | + property real selectedXTranslate |
2694 | + property real selectedAngle |
2695 | + property real selectedScale |
2696 | + property real selectedOpacity |
2697 | + property real selectedTopMarginProgress |
2698 | + |
2699 | + // Those values are needed as target values for the end of phase 1. |
2700 | + // As they are static values, lets calculate them once when entering phase 1 instead of calculating them in each animation pass. |
2701 | + property real phase2startTranslate |
2702 | + property real phase2startAngle |
2703 | + property real phase2startScale |
2704 | + property real phase2startTopMarginProgress |
2705 | + |
2706 | + function snapshot() { |
2707 | + selectedProgress = root.progress; |
2708 | + selectedXTranslate = xTranslate; |
2709 | + selectedAngle = angle; |
2710 | + selectedScale = scale; |
2711 | + selectedOpacity = opacity; |
2712 | + selectedTopMarginProgress = topMarginProgress; |
2713 | + } |
2714 | + |
2715 | + // This calculates how much negative progress there can be if unwinding the spread completely |
2716 | + // the progress for each tile starts at 0 when it crosses the right edge, so the later a tile comes in, |
2717 | + // the bigger its negativeProgress can be. |
2718 | + property real negativeProgress: { |
2719 | + if (index == 1 && spreadView.phase < 2) { |
2720 | + return 0; |
2721 | + } |
2722 | + return -index * spreadView.tileDistance / spreadView.width; |
2723 | + } |
2724 | + |
2725 | + function linearAnimation(startProgress, endProgress, startValue, endValue, progress) { |
2726 | + // progress : progressDiff = value : valueDiff => value = progress * valueDiff / progressDiff |
2727 | + return (progress - startProgress) * (endValue - startValue) / (endProgress - startProgress) + startValue; |
2728 | + } |
2729 | + |
2730 | + function easingAnimation(startProgress, endProgress, startValue, endValue, progress) { |
2731 | + helperEasingCurve.progress = progress - startProgress; |
2732 | + helperEasingCurve.period = endProgress - startProgress; |
2733 | + return helperEasingCurve.value * (endValue - startValue) + startValue; |
2734 | + } |
2735 | + |
2736 | + property real animatedEndDistance: linearAnimation(0, 2, root.endDistance, 0, root.progress) |
2737 | + |
2738 | + // The following blocks handle the animation of the tile in the spread. |
2739 | + // At the beginning, each tile is attached at the right edge, outside the screen. |
2740 | + // The progress for each tile starts at 0 and it reaches its end position at a progress of 1. |
2741 | + // The first phases are handled special for the first 2 tiles. as we do the alt-tab and snapping in there |
2742 | + // Once we reached phase 3, the animation is the same for all tiles. |
2743 | + // When a tile is selected, the animation state is snapshotted, and the spreadView is unwound (progress animates |
2744 | + // back to negativeProgress). All tiles are kept in place and faded out to 0 opacity except |
2745 | + // the selected tile, which is animated from the snapshotted position to be fullscreen. |
2746 | + |
2747 | + property real xTranslate: { |
2748 | + if (otherSelected) { |
2749 | + if (spreadView.phase < 2 && index == 0) { |
2750 | + return linearAnimation(selectedProgress, negativeProgress, |
2751 | + selectedXTranslate, selectedXTranslate - spreadView.tileDistance, root.progress); |
2752 | + } |
2753 | + |
2754 | + return selectedXTranslate; |
2755 | + } |
2756 | + |
2757 | + switch (index) { |
2758 | + case 0: |
2759 | + if (spreadView.phase == 0) { |
2760 | + return Math.min(0, linearAnimation(0, spreadView.positionMarker2, |
2761 | + 0, -spreadView.width * .25, root.animatedProgress)); |
2762 | + } else if (spreadView.phase == 1){ |
2763 | + return linearAnimation(spreadView.positionMarker2, spreadView.positionMarker4, |
2764 | + -spreadView.width * .25, priv.phase2startTranslate, root.progress); |
2765 | + } else if (!priv.isSelected){ // phase 2 |
2766 | + // Apply the same animation as with the rest but add spreadView.width to align it with the others. |
2767 | + return -easingCurve.value * spreadView.width + spreadView.width; |
2768 | + } else if (priv.isSelected) { |
2769 | + return linearAnimation(selectedProgress, negativeProgress, selectedXTranslate, 0, root.progress); |
2770 | + } |
2771 | + |
2772 | + case 1: |
2773 | + if (spreadView.phase == 0 && !priv.isSelected) { |
2774 | + return linearAnimation(0, spreadView.positionMarker2, |
2775 | + 0, -spreadView.width * spreadView.snapPosition, root.animatedProgress); |
2776 | + } else if (spreadView.phase == 1 && !priv.isSelected) { |
2777 | + return linearAnimation(spreadView.positionMarker2, spreadView.positionMarker4, |
2778 | + -spreadView.width * spreadView.snapPosition, priv.phase2startTranslate, |
2779 | + root.progress); |
2780 | + } |
2781 | + } |
2782 | + |
2783 | + if (priv.isSelected) { |
2784 | + // Distance to left edge |
2785 | + var targetTranslate = -spreadView.width - ((index - 1) * root.startDistance); |
2786 | + return linearAnimation(selectedProgress, negativeProgress, |
2787 | + selectedXTranslate, targetTranslate, root.progress); |
2788 | + } |
2789 | + |
2790 | + // Fix it at the right edge... |
2791 | + var rightEdgeOffset = -((index - 1) * root.startDistance); |
2792 | + // ...and use our easing to move them to the left. Stop a bit earlier for each tile |
2793 | + return -easingCurve.value * spreadView.width + (index * animatedEndDistance) + rightEdgeOffset; |
2794 | + |
2795 | + } |
2796 | + |
2797 | + property real angle: { |
2798 | + if (priv.otherSelected) { |
2799 | + return priv.selectedAngle; |
2800 | + } |
2801 | + if (priv.isSelected) { |
2802 | + return linearAnimation(selectedProgress, negativeProgress, selectedAngle, 0, root.progress); |
2803 | + } |
2804 | + switch (index) { |
2805 | + case 0: |
2806 | + if (spreadView.phase == 0) { |
2807 | + return Math.max(0, linearAnimation(0, spreadView.positionMarker2, |
2808 | + 0, root.tile0SnapAngle, root.animatedProgress)); |
2809 | + } else if (spreadView.phase == 1) { |
2810 | + return linearAnimation(spreadView.positionMarker2, spreadView.positionMarker4, |
2811 | + root.tile0SnapAngle, phase2startAngle, root.progress); |
2812 | + } |
2813 | + case 1: |
2814 | + if (spreadView.phase == 0) { |
2815 | + return linearAnimation(0, spreadView.positionMarker2, root.startAngle, |
2816 | + root.startAngle * (1-spreadView.snapPosition), root.animatedProgress); |
2817 | + } else if (spreadView.phase == 1) { |
2818 | + return linearAnimation(spreadView.positionMarker2, spreadView.positionMarker4, |
2819 | + root.startAngle * (1-spreadView.snapPosition), priv.phase2startAngle, |
2820 | + root.progress); |
2821 | + } |
2822 | + } |
2823 | + return root.startAngle - easingCurve.value * (root.startAngle - root.endAngle); |
2824 | + } |
2825 | + |
2826 | + property real scale: { |
2827 | + if (priv.otherSelected) { |
2828 | + return priv.selectedScale; |
2829 | + } |
2830 | + if (priv.isSelected) { |
2831 | + return linearAnimation(selectedProgress, negativeProgress, selectedScale, 1, root.progress); |
2832 | + } |
2833 | + |
2834 | + switch (index) { |
2835 | + case 0: |
2836 | + if (spreadView.phase == 0) { |
2837 | + return 1; |
2838 | + } else if (spreadView.phase == 1) { |
2839 | + return linearAnimation(spreadView.positionMarker2, spreadView.positionMarker4, |
2840 | + 1, phase2startScale, root.progress); |
2841 | + } |
2842 | + case 1: |
2843 | + if (spreadView.phase == 0) { |
2844 | + var targetScale = tile1StartScale - ((tile1StartScale - 1) * spreadView.snapPosition); |
2845 | + return linearAnimation(0, spreadView.positionMarker2, |
2846 | + root.tile1StartScale, targetScale, root.animatedProgress); |
2847 | + } else if (spreadView.phase == 1) { |
2848 | + var startScale = tile1StartScale - ((tile1StartScale - 1) * spreadView.snapPosition); |
2849 | + return linearAnimation(spreadView.positionMarker2, spreadView.positionMarker4, |
2850 | + startScale, priv.phase2startScale, root.progress); |
2851 | + } |
2852 | + } |
2853 | + return root.startScale - easingCurve.value * (root.startScale - root.endScale); |
2854 | + } |
2855 | + |
2856 | + property real opacity: { |
2857 | + if (priv.otherSelected) { |
2858 | + return linearAnimation (selectedProgress, Math.max(0, selectedProgress - .5), |
2859 | + selectedOpacity, 0, root.progress); |
2860 | + } |
2861 | + if (index == 0) { |
2862 | + switch (spreadView.phase) { |
2863 | + case 0: |
2864 | + return linearAnimation(0, spreadView.positionMarker2, 1, .3, root.animatedProgress); |
2865 | + case 1: |
2866 | + return linearAnimation(spreadView.positionMarker2, spreadView.positionMarker4, |
2867 | + .3, 1, root.animatedProgress); |
2868 | + } |
2869 | + } |
2870 | + |
2871 | + return 1; |
2872 | + } |
2873 | + |
2874 | + property real topMarginProgress: { |
2875 | + if (priv.isSelected) { |
2876 | + return linearAnimation(selectedProgress, negativeProgress, selectedTopMarginProgress, 0, root.progress); |
2877 | + } |
2878 | + |
2879 | + switch (index) { |
2880 | + case 0: |
2881 | + if (spreadView.phase == 0) { |
2882 | + return 0; |
2883 | + } else if (spreadView.phase == 1) { |
2884 | + return linearAnimation(spreadView.positionMarker2, spreadView.positionMarker4, |
2885 | + 0, priv.phase2startTopMarginProgress, root.progress); |
2886 | + } |
2887 | + break; |
2888 | + case 1: |
2889 | + if (spreadView.phase == 0) { |
2890 | + return 0; |
2891 | + } else if (spreadView.phase == 1) { |
2892 | + return linearAnimation(spreadView.positionMarker2, spreadView.positionMarker4, |
2893 | + 0, priv.phase2startTopMarginProgress, root.progress); |
2894 | + } |
2895 | + } |
2896 | + |
2897 | + return easingCurve.value; |
2898 | + } |
2899 | + } |
2900 | + |
2901 | + transform: [ |
2902 | + Rotation { |
2903 | + origin { x: 0; y: spreadView.height / 2 } |
2904 | + axis { x: 0; y: 1; z: 0 } |
2905 | + angle: priv.angle |
2906 | + }, |
2907 | + Scale { |
2908 | + origin { x: 0; y: spreadView.height / 2 } |
2909 | + xScale: priv.scale |
2910 | + yScale: xScale |
2911 | + }, |
2912 | + Translate { |
2913 | + x: priv.xTranslate |
2914 | + } |
2915 | + ] |
2916 | + opacity: priv.opacity |
2917 | + topMarginProgress: priv.topMarginProgress |
2918 | + |
2919 | + EasingCurve { |
2920 | + id: easingCurve |
2921 | + type: EasingCurve.OutSine |
2922 | + period: 1 - spreadView.positionMarker2 |
2923 | + progress: root.animatedProgress |
2924 | + } |
2925 | + |
2926 | + // This is used as a calculation helper to figure values for progress other than the current one |
2927 | + // Do not bind anything to this... |
2928 | + EasingCurve { |
2929 | + id: helperEasingCurve |
2930 | + type: easingCurve.type |
2931 | + period: easingCurve.period |
2932 | + } |
2933 | +} |
2934 | |
2935 | === added directory 'qml/Stages/graphics' |
2936 | === added file 'qml/Stages/graphics/dropshadow.png' |
2937 | Binary files qml/Stages/graphics/dropshadow.png 1970-01-01 00:00:00 +0000 and qml/Stages/graphics/dropshadow.png 2014-03-25 15:08:15 +0000 differ |
2938 | === renamed file 'qml/SideStage/graphics/sidestage_handle@20.png' => 'qml/Stages/graphics/sidestage_handle@20.png' |
2939 | === renamed file 'qml/SideStage/graphics/sidestage_handle@20.sci' => 'qml/Stages/graphics/sidestage_handle@20.sci' |
2940 | === modified file 'run_on_device' |
2941 | --- run_on_device 2013-11-27 11:47:14 +0000 |
2942 | +++ run_on_device 2014-03-25 15:08:15 +0000 |
2943 | @@ -103,6 +103,7 @@ |
2944 | ARGS="$ARGS -k" |
2945 | fi |
2946 | |
2947 | + exec_with_ssh "killall -9 dialer-app; killall -9 gallery-app; killall -9 messaging-app; killall -9 address-book-app; killall -9 webbrowser-app" |
2948 | exec_with_ssh "stop unity8" |
2949 | exec_with_ssh "start maliit-server" |
2950 | exec_with_ssh "cd $CODE_DIR/ && ./run $ARGS -- $RUN_OPTIONS" |
2951 | |
2952 | === modified file 'tests/autopilot/unity8/shell/emulators/dash.py' |
2953 | --- tests/autopilot/unity8/shell/emulators/dash.py 2014-03-17 10:42:57 +0000 |
2954 | +++ tests/autopilot/unity8/shell/emulators/dash.py 2014-03-25 15:08:15 +0000 |
2955 | @@ -80,10 +80,7 @@ |
2956 | 'No scope found with id {0}'.format(scope_id)) |
2957 | |
2958 | def _get_scope_from_loader(self, loader): |
2959 | - if loader.scopeId == 'clickscope': |
2960 | - return loader.select_single(DashApps) |
2961 | - else: |
2962 | - return loader.select_single(GenericScopeView) |
2963 | + return loader.select_single(GenericScopeView) |
2964 | |
2965 | def _open_scope_scrolling(self, scope_loader): |
2966 | scroll = self._get_scroll_direction(scope_loader) |
2967 | @@ -164,10 +161,6 @@ |
2968 | raise emulators.UnityEmulatorException( |
2969 | 'No category found with name {}'.format(category)) |
2970 | |
2971 | - |
2972 | -class DashApps(GenericScopeView): |
2973 | - """Autopilot emulator for the applications scope.""" |
2974 | - |
2975 | def get_applications(self, category): |
2976 | """Return the list of applications on a category. |
2977 | |
2978 | |
2979 | === modified file 'tests/autopilot/unity8/shell/emulators/main_window.py' |
2980 | --- tests/autopilot/unity8/shell/emulators/main_window.py 2014-03-02 04:44:30 +0000 |
2981 | +++ tests/autopilot/unity8/shell/emulators/main_window.py 2014-03-25 15:08:15 +0000 |
2982 | @@ -112,4 +112,4 @@ |
2983 | |
2984 | def get_current_focused_app_id(self): |
2985 | """Return the id of the focused application.""" |
2986 | - return self.select_single('Shell').currentFocusedAppId |
2987 | + return self.select_single('Shell').focusedApplicationId |
2988 | |
2989 | === modified file 'tests/autopilot/unity8/shell/tests/test_emulators.py' |
2990 | --- tests/autopilot/unity8/shell/tests/test_emulators.py 2014-03-17 10:42:57 +0000 |
2991 | +++ tests/autopilot/unity8/shell/tests/test_emulators.py 2014-03-25 15:08:15 +0000 |
2992 | @@ -128,7 +128,7 @@ |
2993 | scope_id = 'clickscope' |
2994 | scope = self.dash.open_scope(scope_id) |
2995 | self._assert_scope_is_opened(scope, scope_id) |
2996 | - self.assertIsInstance(scope, dash_emulators.DashApps) |
2997 | + self.assertIsInstance(scope, dash_emulators.GenericScopeView) |
2998 | |
2999 | |
3000 | class GenericScopeViewEmulatorTestCase(DashBaseTestCase): |
3001 | |
3002 | === modified file 'tests/mocks/Unity/Application/ApplicationInfo.cpp' |
3003 | --- tests/mocks/Unity/Application/ApplicationInfo.cpp 2013-09-05 12:21:35 +0000 |
3004 | +++ tests/mocks/Unity/Application/ApplicationInfo.cpp 2014-03-25 15:08:15 +0000 |
3005 | @@ -20,6 +20,7 @@ |
3006 | #include <QQuickItem> |
3007 | #include <QQuickView> |
3008 | #include <QQmlComponent> |
3009 | +#include <QTimer> |
3010 | |
3011 | ApplicationInfo::ApplicationInfo(const QString &appId, QObject *parent) |
3012 | : ApplicationInfoInterface(appId, parent) |
3013 | @@ -32,6 +33,7 @@ |
3014 | ,m_windowComponent(0) |
3015 | ,m_parentItem(0) |
3016 | { |
3017 | + QTimer::singleShot(300, this, SLOT(setRunning())); |
3018 | } |
3019 | |
3020 | ApplicationInfo::ApplicationInfo(QObject *parent) |
3021 | @@ -44,6 +46,7 @@ |
3022 | ,m_windowComponent(0) |
3023 | ,m_parentItem(0) |
3024 | { |
3025 | + QTimer::singleShot(300, this, SLOT(setRunning())); |
3026 | } |
3027 | |
3028 | void ApplicationInfo::onWindowComponentStatusChanged(QQmlComponent::Status status) |
3029 | @@ -52,6 +55,12 @@ |
3030 | doCreateWindowItem(); |
3031 | } |
3032 | |
3033 | +void ApplicationInfo::setRunning() |
3034 | +{ |
3035 | + m_state = Running; |
3036 | + Q_EMIT stateChanged(); |
3037 | +} |
3038 | + |
3039 | void ApplicationInfo::createWindowComponent() |
3040 | { |
3041 | // The assumptions I make here really should hold. |
3042 | |
3043 | === modified file 'tests/mocks/Unity/Application/ApplicationInfo.h' |
3044 | --- tests/mocks/Unity/Application/ApplicationInfo.h 2013-10-11 11:37:04 +0000 |
3045 | +++ tests/mocks/Unity/Application/ApplicationInfo.h 2014-03-25 15:08:15 +0000 |
3046 | @@ -74,6 +74,7 @@ |
3047 | IMPLEMENT_PROPERTY(fullscreen, Fullscreen, bool) |
3048 | IMPLEMENT_PROPERTY(imageQml, ImageQml, QString) |
3049 | IMPLEMENT_PROPERTY(windowQml, WindowQml, QString) |
3050 | + IMPLEMENT_PROPERTY(screenshot, Screenshot, QUrl) |
3051 | |
3052 | #undef IMPLEMENT_PROPERTY |
3053 | |
3054 | @@ -83,6 +84,7 @@ |
3055 | |
3056 | private Q_SLOTS: |
3057 | void onWindowComponentStatusChanged(QQmlComponent::Status status); |
3058 | + void setRunning(); |
3059 | |
3060 | private: |
3061 | void createWindowItem(); |
3062 | |
3063 | === modified file 'tests/mocks/Unity/Application/ApplicationManager.cpp' |
3064 | --- tests/mocks/Unity/Application/ApplicationManager.cpp 2013-12-17 16:04:47 +0000 |
3065 | +++ tests/mocks/Unity/Application/ApplicationManager.cpp 2014-03-25 15:08:15 +0000 |
3066 | @@ -24,13 +24,17 @@ |
3067 | #include <QQuickItem> |
3068 | #include <QQuickView> |
3069 | #include <QQmlComponent> |
3070 | +#include <QTimer> |
3071 | +#include <QDateTime> |
3072 | |
3073 | ApplicationManager::ApplicationManager(QObject *parent) |
3074 | : ApplicationManagerInterface(parent) |
3075 | + , m_suspended(false) |
3076 | , m_mainStageComponent(0) |
3077 | , m_mainStage(0) |
3078 | , m_sideStageComponent(0) |
3079 | , m_sideStage(0) |
3080 | + , m_rightMargin(0) |
3081 | { |
3082 | buildListOfAvailableApplications(); |
3083 | } |
3084 | @@ -63,6 +67,8 @@ |
3085 | return app->state(); |
3086 | case RoleFocused: |
3087 | return app->focused(); |
3088 | + case RoleScreenshot: |
3089 | + return app->screenshot(); |
3090 | default: |
3091 | return QVariant(); |
3092 | } |
3093 | @@ -84,13 +90,16 @@ |
3094 | } |
3095 | |
3096 | void ApplicationManager::add(ApplicationInfo *application) { |
3097 | - if (!application) |
3098 | + if (!application) { |
3099 | return; |
3100 | + } |
3101 | |
3102 | beginInsertRows(QModelIndex(), m_runningApplications.size(), m_runningApplications.size()); |
3103 | m_runningApplications.append(application); |
3104 | endInsertRows(); |
3105 | + Q_EMIT applicationAdded(application->appId()); |
3106 | Q_EMIT countChanged(); |
3107 | + Q_EMIT focusRequested(application->appId()); |
3108 | } |
3109 | |
3110 | void ApplicationManager::remove(ApplicationInfo *application) { |
3111 | @@ -99,6 +108,7 @@ |
3112 | beginRemoveRows(QModelIndex(), i, i); |
3113 | m_runningApplications.removeAt(i); |
3114 | endRemoveRows(); |
3115 | + Q_EMIT applicationRemoved(application->appId()); |
3116 | Q_EMIT countChanged(); |
3117 | } |
3118 | } |
3119 | @@ -171,6 +181,8 @@ |
3120 | } |
3121 | add(application); |
3122 | |
3123 | + QMetaObject::invokeMethod(this, "focusApplication", Qt::QueuedConnection, Q_ARG(QString, appId)); |
3124 | + |
3125 | return application; |
3126 | } |
3127 | |
3128 | @@ -180,8 +192,32 @@ |
3129 | if (application == nullptr) |
3130 | return false; |
3131 | |
3132 | + if (application->appId() == focusedApplicationId()) { |
3133 | + unfocusCurrentApplication(); |
3134 | + } |
3135 | remove(application); |
3136 | - Q_EMIT focusedApplicationIdChanged(); |
3137 | + return true; |
3138 | +} |
3139 | + |
3140 | +bool ApplicationManager::updateScreenshot(const QString &appId) |
3141 | +{ |
3142 | + int idx = -1; |
3143 | + ApplicationInfo *application = nullptr; |
3144 | + for (int i = 0; i < m_availableApplications.count(); ++i) { |
3145 | + application = m_availableApplications.at(i); |
3146 | + if (application->appId() == appId) { |
3147 | + idx = i; |
3148 | + break; |
3149 | + } |
3150 | + } |
3151 | + |
3152 | + if (idx == -1) { |
3153 | + return false; |
3154 | + } |
3155 | + |
3156 | + application->setScreenshot(QString("image://application/%1/%2").arg(appId).arg(QDateTime::currentMSecsSinceEpoch())); |
3157 | + QModelIndex appIndex = index(idx); |
3158 | + Q_EMIT dataChanged(appIndex, appIndex, QVector<int>() << RoleScreenshot); |
3159 | return true; |
3160 | } |
3161 | |
3162 | @@ -194,6 +230,25 @@ |
3163 | return QString(); |
3164 | } |
3165 | |
3166 | +bool ApplicationManager::suspended() const |
3167 | +{ |
3168 | + return m_suspended; |
3169 | +} |
3170 | + |
3171 | +void ApplicationManager::setSuspended(bool suspended) |
3172 | +{ |
3173 | + ApplicationInfo *focusedApp = findApplication(focusedApplicationId()); |
3174 | + if (focusedApp) { |
3175 | + if (suspended) { |
3176 | + focusedApp->setState(ApplicationInfo::Suspended); |
3177 | + } else { |
3178 | + focusedApp->setState(ApplicationInfo::Running); |
3179 | + } |
3180 | + } |
3181 | + m_suspended = suspended; |
3182 | + Q_EMIT suspendedChanged(); |
3183 | +} |
3184 | + |
3185 | bool ApplicationManager::focusApplication(const QString &appId) |
3186 | { |
3187 | ApplicationInfo *application = findApplication(appId); |
3188 | @@ -242,6 +297,15 @@ |
3189 | return true; |
3190 | } |
3191 | |
3192 | +bool ApplicationManager::requestFocusApplication(const QString &appId) |
3193 | +{ |
3194 | + if (appId != focusedApplicationId()) { |
3195 | + QMetaObject::invokeMethod(this, "focusRequested", Qt::QueuedConnection, Q_ARG(QString, appId)); |
3196 | + return true; |
3197 | + } |
3198 | + return false; |
3199 | +} |
3200 | + |
3201 | void ApplicationManager::unfocusCurrentApplication() |
3202 | { |
3203 | for (ApplicationInfo *app : m_runningApplications) { |
3204 | @@ -270,10 +334,12 @@ |
3205 | "Image {\n" |
3206 | " anchors.fill: parent\n" |
3207 | " anchors.topMargin: %1\n" |
3208 | - " source: \"file://%2/Dash/graphics/phone/screenshots/%3.png\"\n" |
3209 | + " anchors.rightMargin: %2\n" |
3210 | + " source: \"file://%3/Dash/graphics/phone/screenshots/%4.png\"\n" |
3211 | " smooth: true\n" |
3212 | " fillMode: Image.PreserveAspectCrop\n" |
3213 | "}").arg(topMargin) |
3214 | + .arg(m_rightMargin) |
3215 | .arg(qmlDirectory()) |
3216 | .arg(application->icon().toString()); |
3217 | application->setWindowQml(windowQml); |
3218 | @@ -299,6 +365,7 @@ |
3219 | application->setName("Phone"); |
3220 | application->setIcon(QUrl("phone")); |
3221 | application->setStage(ApplicationInfo::SideStage); |
3222 | + application->setScreenshot(QString("image://application/%1/%2").arg(application->appId()).arg(QDateTime::currentMSecsSinceEpoch())); |
3223 | generateQmlStrings(application); |
3224 | m_availableApplications.append(application); |
3225 | |
3226 | @@ -307,6 +374,7 @@ |
3227 | application->setName("Camera"); |
3228 | application->setIcon(QUrl("camera")); |
3229 | application->setFullscreen(true); |
3230 | + application->setScreenshot(QString("image://application/%1/%2").arg(application->appId()).arg(QDateTime::currentMSecsSinceEpoch())); |
3231 | generateQmlStrings(application); |
3232 | m_availableApplications.append(application); |
3233 | |
3234 | @@ -314,6 +382,7 @@ |
3235 | application->setAppId("gallery-app"); |
3236 | application->setName("Gallery"); |
3237 | application->setIcon(QUrl("gallery")); |
3238 | + application->setScreenshot(QString("image://application/%1/%2").arg(application->appId()).arg(QDateTime::currentMSecsSinceEpoch())); |
3239 | generateQmlStrings(application); |
3240 | m_availableApplications.append(application); |
3241 | |
3242 | @@ -322,13 +391,16 @@ |
3243 | application->setName("Facebook"); |
3244 | application->setIcon(QUrl("facebook")); |
3245 | application->setStage(ApplicationInfo::SideStage); |
3246 | + application->setScreenshot(QString("image://application/%1/%2").arg(application->appId()).arg(QDateTime::currentMSecsSinceEpoch())); |
3247 | generateQmlStrings(application); |
3248 | m_availableApplications.append(application); |
3249 | |
3250 | application = new ApplicationInfo(this); |
3251 | application->setAppId("webbrowser-app"); |
3252 | + application->setFullscreen(true); |
3253 | application->setName("Browser"); |
3254 | application->setIcon(QUrl("browser")); |
3255 | + application->setScreenshot(QString("image://application/%1/%2").arg(application->appId()).arg(QDateTime::currentMSecsSinceEpoch())); |
3256 | generateQmlStrings(application); |
3257 | m_availableApplications.append(application); |
3258 | |
3259 | @@ -337,6 +409,7 @@ |
3260 | application->setName("Twitter"); |
3261 | application->setIcon(QUrl("twitter")); |
3262 | application->setStage(ApplicationInfo::SideStage); |
3263 | + application->setScreenshot(QString("image://application/%1/%2").arg(application->appId()).arg(QDateTime::currentMSecsSinceEpoch())); |
3264 | generateQmlStrings(application); |
3265 | m_availableApplications.append(application); |
3266 | |
3267 | @@ -344,6 +417,7 @@ |
3268 | application->setAppId("gmail-webapp"); |
3269 | application->setName("GMail"); |
3270 | application->setIcon(QUrl("gmail")); |
3271 | + application->setScreenshot(QString("image://application/%1/%2").arg(application->appId()).arg(QDateTime::currentMSecsSinceEpoch())); |
3272 | m_availableApplications.append(application); |
3273 | |
3274 | application = new ApplicationInfo(this); |
3275 | @@ -351,6 +425,7 @@ |
3276 | application->setName("Weather"); |
3277 | application->setIcon(QUrl("weather")); |
3278 | application->setStage(ApplicationInfo::SideStage); |
3279 | + application->setScreenshot(QString("image://application/%1/%2").arg(application->appId()).arg(QDateTime::currentMSecsSinceEpoch())); |
3280 | generateQmlStrings(application); |
3281 | m_availableApplications.append(application); |
3282 | |
3283 | @@ -359,6 +434,7 @@ |
3284 | application->setName("Notepad"); |
3285 | application->setIcon(QUrl("notepad")); |
3286 | application->setStage(ApplicationInfo::SideStage); |
3287 | + application->setScreenshot(QString("image://application/%1/%2").arg(application->appId()).arg(QDateTime::currentMSecsSinceEpoch())); |
3288 | m_availableApplications.append(application); |
3289 | |
3290 | application = new ApplicationInfo(this); |
3291 | @@ -366,6 +442,7 @@ |
3292 | application->setName("Calendar"); |
3293 | application->setIcon(QUrl("calendar")); |
3294 | application->setStage(ApplicationInfo::SideStage); |
3295 | + application->setScreenshot(QString("image://application/%1/%2").arg(application->appId()).arg(QDateTime::currentMSecsSinceEpoch())); |
3296 | m_availableApplications.append(application); |
3297 | |
3298 | application = new ApplicationInfo(this); |
3299 | @@ -373,18 +450,21 @@ |
3300 | application->setName("Media Player"); |
3301 | application->setIcon(QUrl("mediaplayer-app")); |
3302 | application->setFullscreen(true); |
3303 | + application->setScreenshot(QString("image://application/%1/%2").arg(application->appId()).arg(QDateTime::currentMSecsSinceEpoch())); |
3304 | m_availableApplications.append(application); |
3305 | |
3306 | application = new ApplicationInfo(this); |
3307 | application->setAppId("evernote"); |
3308 | application->setName("Evernote"); |
3309 | application->setIcon(QUrl("evernote")); |
3310 | + application->setScreenshot(QString("image://application/%1/%2").arg(application->appId()).arg(QDateTime::currentMSecsSinceEpoch())); |
3311 | m_availableApplications.append(application); |
3312 | |
3313 | application = new ApplicationInfo(this); |
3314 | application->setAppId("map"); |
3315 | application->setName("Map"); |
3316 | application->setIcon(QUrl("map")); |
3317 | + application->setScreenshot(QString("image://application/%1/%2").arg(application->appId()).arg(QDateTime::currentMSecsSinceEpoch())); |
3318 | generateQmlStrings(application); |
3319 | m_availableApplications.append(application); |
3320 | |
3321 | @@ -392,24 +472,28 @@ |
3322 | application->setAppId("pinterest"); |
3323 | application->setName("Pinterest"); |
3324 | application->setIcon(QUrl("pinterest")); |
3325 | + application->setScreenshot(QString("image://application/%1/%2").arg(application->appId()).arg(QDateTime::currentMSecsSinceEpoch())); |
3326 | m_availableApplications.append(application); |
3327 | |
3328 | application = new ApplicationInfo(this); |
3329 | application->setAppId("soundcloud"); |
3330 | application->setName("SoundCloud"); |
3331 | application->setIcon(QUrl("soundcloud")); |
3332 | + application->setScreenshot(QString("image://application/%1/%2").arg(application->appId()).arg(QDateTime::currentMSecsSinceEpoch())); |
3333 | m_availableApplications.append(application); |
3334 | |
3335 | application = new ApplicationInfo(this); |
3336 | application->setAppId("wikipedia"); |
3337 | application->setName("Wikipedia"); |
3338 | application->setIcon(QUrl("wikipedia")); |
3339 | + application->setScreenshot(QString("image://application/%1/%2").arg(application->appId()).arg(QDateTime::currentMSecsSinceEpoch())); |
3340 | m_availableApplications.append(application); |
3341 | |
3342 | application = new ApplicationInfo(this); |
3343 | application->setAppId("youtube"); |
3344 | application->setName("YouTube"); |
3345 | application->setIcon(QUrl("youtube")); |
3346 | + application->setScreenshot(QString("image://application/%1/%2").arg(application->appId()).arg(QDateTime::currentMSecsSinceEpoch())); |
3347 | m_availableApplications.append(application); |
3348 | } |
3349 | |
3350 | @@ -484,3 +568,25 @@ |
3351 | m_sideStage->setParentItem(shell); |
3352 | m_sideStage->setFlag(QQuickItem::ItemHasContents, false); |
3353 | } |
3354 | + |
3355 | +QStringList ApplicationManager::availableApplications() |
3356 | +{ |
3357 | + QStringList appIds; |
3358 | + Q_FOREACH(ApplicationInfo *app, m_availableApplications) { |
3359 | + appIds << app->appId(); |
3360 | + } |
3361 | + return appIds; |
3362 | +} |
3363 | + |
3364 | +int ApplicationManager::rightMargin() const |
3365 | +{ |
3366 | + return m_rightMargin; |
3367 | +} |
3368 | + |
3369 | +void ApplicationManager::setRightMargin(int rightMargin) |
3370 | +{ |
3371 | + m_rightMargin = rightMargin; |
3372 | + Q_FOREACH(ApplicationInfo *app, m_availableApplications) { |
3373 | + generateQmlStrings(app); |
3374 | + } |
3375 | +} |
3376 | |
3377 | === modified file 'tests/mocks/Unity/Application/ApplicationManager.h' |
3378 | --- tests/mocks/Unity/Application/ApplicationManager.h 2013-10-11 11:37:04 +0000 |
3379 | +++ tests/mocks/Unity/Application/ApplicationManager.h 2014-03-25 15:08:15 +0000 |
3380 | @@ -45,6 +45,10 @@ |
3381 | |
3382 | Q_PROPERTY(bool fake READ fake CONSTANT) |
3383 | |
3384 | + // Only for testing |
3385 | + // This can be used to place some controls to right, like make tryPhoneStage for example |
3386 | + Q_PROPERTY(int rightMargin READ rightMargin WRITE setRightMargin) |
3387 | + |
3388 | public: |
3389 | ApplicationManager(QObject *parent = NULL); |
3390 | virtual ~ApplicationManager(); |
3391 | @@ -87,13 +91,22 @@ |
3392 | Q_INVOKABLE void move(int from, int to); |
3393 | |
3394 | // Application control methods |
3395 | + Q_INVOKABLE bool requestFocusApplication(const QString &appId) override; |
3396 | Q_INVOKABLE bool focusApplication(const QString &appId) override; |
3397 | Q_INVOKABLE void unfocusCurrentApplication() override; |
3398 | Q_INVOKABLE ApplicationInfo *startApplication(const QString &appId, const QStringList &arguments = QStringList()) override; |
3399 | Q_INVOKABLE ApplicationInfo *startApplication(const QString &appId, ExecFlags flags, const QStringList &arguments = QStringList()); |
3400 | Q_INVOKABLE bool stopApplication(const QString &appId) override; |
3401 | + Q_INVOKABLE bool updateScreenshot(const QString &appId) override; |
3402 | |
3403 | QString focusedApplicationId() const override; |
3404 | + bool suspended() const; |
3405 | + void setSuspended(bool suspended); |
3406 | + |
3407 | + // Only for testing |
3408 | + Q_INVOKABLE QStringList availableApplications(); |
3409 | + int rightMargin() const; |
3410 | + void setRightMargin(int rightMargin); |
3411 | |
3412 | Q_SIGNALS: |
3413 | void keyboardHeightChanged(); |
3414 | @@ -113,12 +126,15 @@ |
3415 | void createSideStage(); |
3416 | int m_keyboardHeight; |
3417 | bool m_keyboardVisible; |
3418 | + bool m_suspended; |
3419 | QList<ApplicationInfo*> m_runningApplications; |
3420 | QList<ApplicationInfo*> m_availableApplications; |
3421 | QQmlComponent *m_mainStageComponent; |
3422 | QQuickItem *m_mainStage; |
3423 | QQmlComponent *m_sideStageComponent; |
3424 | QQuickItem *m_sideStage; |
3425 | + |
3426 | + int m_rightMargin; |
3427 | }; |
3428 | |
3429 | Q_DECLARE_OPERATORS_FOR_FLAGS(ApplicationManager::ExecFlags) |
3430 | |
3431 | === added file 'tests/mocks/Unity/Application/ApplicationScreenshotProvider.cpp' |
3432 | --- tests/mocks/Unity/Application/ApplicationScreenshotProvider.cpp 1970-01-01 00:00:00 +0000 |
3433 | +++ tests/mocks/Unity/Application/ApplicationScreenshotProvider.cpp 2014-03-25 15:08:15 +0000 |
3434 | @@ -0,0 +1,74 @@ |
3435 | +/* |
3436 | + * Copyright (C) 2014 Canonical, Ltd. |
3437 | + * |
3438 | + * This program is free software: you can redistribute it and/or modify it under |
3439 | + * the terms of the GNU Lesser General Public License version 3, as published by |
3440 | + * the Free Software Foundation. |
3441 | + * |
3442 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
3443 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
3444 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
3445 | + * Lesser General Public License for more details. |
3446 | + * |
3447 | + * You should have received a copy of the GNU Lesser General Public License |
3448 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
3449 | + */ |
3450 | + |
3451 | +#include "ApplicationScreenshotProvider.h" |
3452 | +#include "ApplicationManager.h" |
3453 | +#include "ApplicationInfo.h" |
3454 | + |
3455 | +#include "paths.h" |
3456 | + |
3457 | +#include <QDebug> |
3458 | +#include <QGuiApplication> |
3459 | +#include <QWindow> |
3460 | +#include <QQuickWindow> |
3461 | + |
3462 | +ApplicationScreenshotProvider::ApplicationScreenshotProvider(ApplicationManager *appManager) |
3463 | + : QQuickImageProvider(QQuickImageProvider::Image) |
3464 | + , m_appManager(appManager) |
3465 | +{ |
3466 | +} |
3467 | + |
3468 | +QImage ApplicationScreenshotProvider::requestImage(const QString &imageId, QSize * size, |
3469 | + const QSize &requestedSize) |
3470 | +{ |
3471 | + // We ignore requestedSize here intentionally to avoid keeping scaled copies around |
3472 | + Q_UNUSED(requestedSize) |
3473 | + |
3474 | + QString appId = imageId.split('/').first(); |
3475 | + |
3476 | + ApplicationInfo* app = static_cast<ApplicationInfo*>(m_appManager->findApplication(appId)); |
3477 | + if (app == nullptr) { |
3478 | + return QImage(); |
3479 | + } |
3480 | + |
3481 | + QString filePath = QString("%1/Dash/graphics/phone/screenshots/%2@12.png").arg(qmlDirectory()).arg(app->icon().toString()); |
3482 | + |
3483 | + QImage image; |
3484 | + if (!image.load(filePath)) { |
3485 | + qWarning() << "failed loading app image" << filePath; |
3486 | + } |
3487 | + |
3488 | + |
3489 | + if (app->stage() == ApplicationInfo::SideStage) { |
3490 | + QByteArray gus = qgetenv("GRID_UNIT_PX"); |
3491 | + image = image.scaledToWidth(gus.toInt() * 48); |
3492 | + } else { |
3493 | + // Lets scale main stage applications to be the size of the screen/window. |
3494 | + QGuiApplication *unity = qobject_cast<QGuiApplication*>(qApp); |
3495 | + Q_FOREACH (QWindow *win, unity->allWindows()) { |
3496 | + QQuickWindow *quickWin = qobject_cast<QQuickWindow*>(win); |
3497 | + if (quickWin) { |
3498 | + image = image.scaledToWidth(quickWin->width() - m_appManager->rightMargin()); |
3499 | + break; |
3500 | + } |
3501 | + } |
3502 | + } |
3503 | + |
3504 | + size->setWidth(image.width()); |
3505 | + size->setHeight(image.height()); |
3506 | + |
3507 | + return image; |
3508 | +} |
3509 | |
3510 | === added file 'tests/mocks/Unity/Application/ApplicationScreenshotProvider.h' |
3511 | --- tests/mocks/Unity/Application/ApplicationScreenshotProvider.h 1970-01-01 00:00:00 +0000 |
3512 | +++ tests/mocks/Unity/Application/ApplicationScreenshotProvider.h 2014-03-25 15:08:15 +0000 |
3513 | @@ -0,0 +1,34 @@ |
3514 | +/* |
3515 | + * Copyright (C) 201 Canonical, Ltd. |
3516 | + * |
3517 | + * This program is free software: you can redistribute it and/or modify it under |
3518 | + * the terms of the GNU Lesser General Public License version 3, as published by |
3519 | + * the Free Software Foundation. |
3520 | + * |
3521 | + * This program is distributed in the hope that it will be useful, but WITHOUT |
3522 | + * ANY WARRANTY; without even the implied warranties of MERCHANTABILITY, |
3523 | + * SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
3524 | + * Lesser General Public License for more details. |
3525 | + * |
3526 | + * You should have received a copy of the GNU Lesser General Public License |
3527 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
3528 | + */ |
3529 | + |
3530 | +#ifndef APPLICATIONSCREENSHOTPROVIDER_H |
3531 | +#define APPLICATIONSCREENSHOTPROVIDER_H |
3532 | + |
3533 | +#include <QQuickImageProvider> |
3534 | + |
3535 | +class ApplicationManager; |
3536 | +class ApplicationScreenshotProvider : public QQuickImageProvider |
3537 | +{ |
3538 | +public: |
3539 | + explicit ApplicationScreenshotProvider(ApplicationManager *appManager); |
3540 | + |
3541 | + QImage requestImage(const QString &appId, QSize *size, const QSize &requestedSize) override; |
3542 | + |
3543 | +private: |
3544 | + ApplicationManager* m_appManager; |
3545 | +}; |
3546 | + |
3547 | +#endif // APPLICATIONSCREENSHOTPROVIDER_H |
3548 | |
3549 | === modified file 'tests/mocks/Unity/Application/CMakeLists.txt' |
3550 | --- tests/mocks/Unity/Application/CMakeLists.txt 2013-12-13 01:02:53 +0000 |
3551 | +++ tests/mocks/Unity/Application/CMakeLists.txt 2014-03-25 15:08:15 +0000 |
3552 | @@ -5,6 +5,7 @@ |
3553 | ApplicationInfo.cpp |
3554 | ApplicationImage.cpp |
3555 | ApplicationManager.cpp |
3556 | + ApplicationScreenshotProvider.cpp |
3557 | ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationInfoInterface.h |
3558 | ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationManagerInterface.h |
3559 | ) |
3560 | |
3561 | === modified file 'tests/mocks/Unity/Application/plugin.cpp' |
3562 | --- tests/mocks/Unity/Application/plugin.cpp 2013-09-11 15:33:02 +0000 |
3563 | +++ tests/mocks/Unity/Application/plugin.cpp 2014-03-25 15:08:15 +0000 |
3564 | @@ -18,13 +18,20 @@ |
3565 | #include "ApplicationInfo.h" |
3566 | #include "ApplicationImage.h" |
3567 | #include "ApplicationManager.h" |
3568 | +#include "ApplicationScreenshotProvider.h" |
3569 | |
3570 | #include <qqml.h> |
3571 | +#include <QQmlEngine> |
3572 | + |
3573 | +ApplicationManager *s_appManager = 0; |
3574 | |
3575 | static QObject* applicationManagerSingleton(QQmlEngine* engine, QJSEngine* scriptEngine) { |
3576 | - Q_UNUSED(engine); |
3577 | - Q_UNUSED(scriptEngine); |
3578 | - return new ApplicationManager(); |
3579 | + Q_UNUSED(engine); |
3580 | + Q_UNUSED(scriptEngine); |
3581 | + if (!s_appManager) { |
3582 | + s_appManager = new ApplicationManager(); |
3583 | + } |
3584 | + return s_appManager; |
3585 | } |
3586 | |
3587 | void FakeUnityApplicationQmlPlugin::registerTypes(const char *uri) |
3588 | @@ -37,3 +44,11 @@ |
3589 | |
3590 | qmlRegisterType<ApplicationImage>(uri, 0, 1, "ApplicationImage"); |
3591 | } |
3592 | + |
3593 | +void FakeUnityApplicationQmlPlugin::initializeEngine(QQmlEngine *engine, const char *uri) |
3594 | +{ |
3595 | + QQmlExtensionPlugin::initializeEngine(engine, uri); |
3596 | + |
3597 | + ApplicationManager* appManager = static_cast<ApplicationManager*>(applicationManagerSingleton(engine, NULL)); |
3598 | + engine->addImageProvider(QLatin1String("application"), new ApplicationScreenshotProvider(appManager)); |
3599 | +} |
3600 | |
3601 | === modified file 'tests/mocks/Unity/Application/plugin.h' |
3602 | --- tests/mocks/Unity/Application/plugin.h 2013-09-04 13:42:27 +0000 |
3603 | +++ tests/mocks/Unity/Application/plugin.h 2014-03-25 15:08:15 +0000 |
3604 | @@ -25,6 +25,7 @@ |
3605 | Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") |
3606 | public: |
3607 | void registerTypes(const char *uri); |
3608 | + void initializeEngine(QQmlEngine *engine, const char *uri); |
3609 | }; |
3610 | |
3611 | #endif |
3612 | |
3613 | === modified file 'tests/plugins/Unity/Launcher/launchermodeltest.cpp' |
3614 | --- tests/plugins/Unity/Launcher/launchermodeltest.cpp 2013-09-16 17:59:13 +0000 |
3615 | +++ tests/plugins/Unity/Launcher/launchermodeltest.cpp 2014-03-25 15:08:15 +0000 |
3616 | @@ -39,6 +39,7 @@ |
3617 | ApplicationInfoInterface::Stage stage() const { return ApplicationInfoInterface::MainStage; } |
3618 | ApplicationInfoInterface::State state() const { return ApplicationInfoInterface::Running; } |
3619 | bool focused() const { return m_focused; } |
3620 | + QUrl screenshot() const { return QUrl(); } |
3621 | |
3622 | // Methods used for mocking (not in the interface) |
3623 | void setFocused(bool focused) { m_focused = focused; Q_EMIT focusedChanged(focused); } |
3624 | @@ -92,6 +93,10 @@ |
3625 | m_list.takeAt(index)->deleteLater(); |
3626 | endRemoveRows(); |
3627 | } |
3628 | + bool updateScreenshot(const QString &appId) { Q_UNUSED(appId); return true; } |
3629 | + bool requestFocusApplication(const QString &appId) { Q_UNUSED(appId); return true; } |
3630 | + bool suspended() const { return false; } |
3631 | + void setSuspended(bool) {} |
3632 | |
3633 | private: |
3634 | QList<MockApp*> m_list; |
3635 | |
3636 | === modified file 'tests/qmltests/CMakeLists.txt' |
3637 | --- tests/qmltests/CMakeLists.txt 2014-03-17 11:44:05 +0000 |
3638 | +++ tests/qmltests/CMakeLists.txt 2014-03-25 15:08:15 +0000 |
3639 | @@ -83,6 +83,6 @@ |
3640 | ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/QMenuModel") |
3641 | add_qml_test(Panel/Indicators MenuItemFactory IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/plugins) |
3642 | add_qml_test(Panel/Indicators MessageMenuItemFactory IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/plugins) |
3643 | -add_qml_test(SideStage SideStage IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} |
3644 | +add_qml_test(Stages PhoneStage IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} |
3645 | ${CMAKE_BINARY_DIR}/tests/mocks |
3646 | ${CMAKE_BINARY_DIR}/plugins) |
3647 | |
3648 | === modified file 'tests/qmltests/Components/tst_ResponsiveFlowView.qml' |
3649 | --- tests/qmltests/Components/tst_ResponsiveFlowView.qml 2013-12-17 16:04:47 +0000 |
3650 | +++ tests/qmltests/Components/tst_ResponsiveFlowView.qml 2014-03-25 15:08:15 +0000 |
3651 | @@ -82,8 +82,7 @@ |
3652 | ResponsiveFlowView { |
3653 | id: flow |
3654 | anchors.fill: parent |
3655 | - firstModel: fakeModel |
3656 | - secondModel: fakeModel |
3657 | + model: fakeModel |
3658 | minimumHorizontalSpacing: |
3659 | minHSpacingSelector.values[minHSpacingSelector.selectedIndex] |
3660 | verticalSpacing: units.gu(2) |
3661 | |
3662 | === modified file 'tests/qmltests/Dash/Apps/tst_RunningApplicationsGrid.qml' |
3663 | --- tests/qmltests/Dash/Apps/tst_RunningApplicationsGrid.qml 2013-12-17 16:04:47 +0000 |
3664 | +++ tests/qmltests/Dash/Apps/tst_RunningApplicationsGrid.qml 2014-03-25 15:08:15 +0000 |
3665 | @@ -18,87 +18,20 @@ |
3666 | import QtTest 1.0 |
3667 | import "../../../../qml/Dash/Apps" |
3668 | import Unity.Test 0.1 as UT |
3669 | +import Unity.Application 0.1 |
3670 | |
3671 | -Item { |
3672 | +// Using Rectangle to have an opaque surface because AppManager paints app surfaces behind it. |
3673 | +Rectangle { |
3674 | width: units.gu(50) |
3675 | height: units.gu(40) |
3676 | |
3677 | - QtObject { |
3678 | - id: fakeApplicationManager |
3679 | - |
3680 | - property bool sideStageEnabled: false |
3681 | - |
3682 | - function stopApplication(appId) { |
3683 | - for (var i=0, len=fakeRunningAppsModel.count; i<len; i++) { |
3684 | - if (appId == fakeRunningAppsModel.get(i).appId) { |
3685 | - fakeRunningAppsModel.remove(i) |
3686 | - } |
3687 | - } |
3688 | - } |
3689 | - } |
3690 | - |
3691 | - QtObject { |
3692 | - id: shell |
3693 | - property bool dashShown: true |
3694 | - property bool stageScreenshotsReady: false |
3695 | - property var applicationManager: fakeApplicationManager |
3696 | - |
3697 | - function activateApplication(appId) { |
3698 | - } |
3699 | - } |
3700 | - |
3701 | - ListModel { |
3702 | - id: fakeRunningAppsModel |
3703 | - |
3704 | - function contains(appId) { |
3705 | - for (var i=0, len=fakeRunningAppsModel.count; i<len; i++) { |
3706 | - if (appId == fakeRunningAppsModel.get(i).appId) { |
3707 | - return true; |
3708 | - } |
3709 | - } |
3710 | - return false; |
3711 | - } |
3712 | - |
3713 | - function rePopulate() { |
3714 | - for (var i=0, len=availableAppsModel.count; i<len; i++) { |
3715 | - fakeRunningAppsModel.append(availableAppsModel.get(i)); |
3716 | - } |
3717 | - } |
3718 | - } |
3719 | - |
3720 | - ListModel { |
3721 | - id: availableAppsModel |
3722 | - ListElement { |
3723 | - name: "Phone" |
3724 | - icon: "phone-app" |
3725 | - exec: "/usr/bin/phone-app" |
3726 | - appId: "phone" |
3727 | - imageQml: "import QtQuick 2.0\n \ |
3728 | - Rectangle { \n \ |
3729 | - anchors.fill:parent \n \ |
3730 | - color:'darkgreen' \n \ |
3731 | - Text { anchors.centerIn: parent; text: 'PHONE' } \n \ |
3732 | - }" |
3733 | - } |
3734 | - |
3735 | - ListElement { |
3736 | - name: "Calendar" |
3737 | - icon: "calendar-app" |
3738 | - exec: "/usr/bin/calendar-app" |
3739 | - appId: "calendar" |
3740 | - imageQml: "import QtQuick 2.0\n \ |
3741 | - Rectangle { \n \ |
3742 | - anchors.fill:parent \n \ |
3743 | - color:'darkblue' \n \ |
3744 | - Text { anchors.centerIn: parent; text: 'CALENDAR'\n \ |
3745 | - color:'white'} \n \ |
3746 | - }" |
3747 | - } |
3748 | - } |
3749 | - |
3750 | function resetRunningApplications() { |
3751 | - fakeRunningAppsModel.clear() |
3752 | - fakeRunningAppsModel.rePopulate() |
3753 | + while (ApplicationManager.count > 0) { |
3754 | + ApplicationManager.stopApplication(ApplicationManager.get(0).appId) |
3755 | + } |
3756 | + |
3757 | + ApplicationManager.startApplication("phone-app"); |
3758 | + ApplicationManager.startApplication("webbrowser-app"); |
3759 | } |
3760 | |
3761 | Component.onCompleted: { |
3762 | @@ -109,7 +42,7 @@ |
3763 | RunningApplicationsGrid { |
3764 | id: runningApplicationsGrid |
3765 | anchors.fill: parent |
3766 | - firstModel: fakeRunningAppsModel |
3767 | + model: ApplicationManager |
3768 | } |
3769 | |
3770 | UT.UnityTestCase { |
3771 | @@ -121,11 +54,11 @@ |
3772 | resetRunningApplications() |
3773 | } |
3774 | |
3775 | - property var calendarTile |
3776 | + property var browserTile |
3777 | property var phoneTile |
3778 | |
3779 | - property var isCalendarLongPressed: false |
3780 | - function onCalendarLongPressed() {isCalendarLongPressed = true} |
3781 | + property var isBrowserLongPressed: false |
3782 | + function onBrowserLongPressed() {isBrowserLongPressed = true} |
3783 | |
3784 | property var isPhoneLongPressed: false |
3785 | function onPhoneLongPressed() {isPhoneLongPressed = true} |
3786 | @@ -133,25 +66,25 @@ |
3787 | // Tiles should go to termination mode when any one of them is long-pressed. |
3788 | // Long-pressing when they're in termination mode brings them back to activation mode |
3789 | function test_enterTerminationMode() { |
3790 | - calendarTile = findChild(runningApplicationsGrid, "runningAppTile Calendar") |
3791 | - verify(calendarTile != undefined) |
3792 | - calendarTile.onPressAndHold.connect(onCalendarLongPressed) |
3793 | + browserTile = findChild(runningApplicationsGrid, "runningAppTile Browser") |
3794 | + verify(browserTile != undefined) |
3795 | + browserTile.onPressAndHold.connect(onBrowserLongPressed) |
3796 | |
3797 | phoneTile = findChild(runningApplicationsGrid, "runningAppTile Phone") |
3798 | verify(phoneTile != undefined) |
3799 | phoneTile.onPressAndHold.connect(onPhoneLongPressed) |
3800 | |
3801 | - compare(calendarTile.terminationModeEnabled, false) |
3802 | + compare(browserTile.terminationModeEnabled, false) |
3803 | compare(phoneTile.terminationModeEnabled, false) |
3804 | compare(runningApplicationsGrid.terminationModeEnabled, false) |
3805 | |
3806 | - isCalendarLongPressed = false |
3807 | - mousePress(calendarTile, calendarTile.width/2, calendarTile.height/2) |
3808 | + isBrowserLongPressed = false |
3809 | + mousePress(browserTile, browserTile.width/2, browserTile.height/2) |
3810 | tryCompareFunction(checkSwitchToTerminationModeAfterLongPress, true) |
3811 | |
3812 | - mouseRelease(calendarTile, calendarTile.width/2, calendarTile.height/2) |
3813 | + mouseRelease(browserTile, browserTile.width/2, browserTile.height/2) |
3814 | |
3815 | - compare(calendarTile.terminationModeEnabled, true) |
3816 | + compare(browserTile.terminationModeEnabled, true) |
3817 | compare(phoneTile.terminationModeEnabled, true) |
3818 | compare(runningApplicationsGrid.terminationModeEnabled, true) |
3819 | |
3820 | @@ -161,23 +94,23 @@ |
3821 | |
3822 | mouseRelease(phoneTile, phoneTile.width/2, phoneTile.height/2) |
3823 | |
3824 | - compare(calendarTile.terminationModeEnabled, false) |
3825 | + compare(browserTile.terminationModeEnabled, false) |
3826 | compare(phoneTile.terminationModeEnabled, false) |
3827 | compare(runningApplicationsGrid.terminationModeEnabled, false) |
3828 | |
3829 | - calendarTile.onPressAndHold.disconnect(onCalendarLongPressed) |
3830 | + browserTile.onPressAndHold.disconnect(onBrowserLongPressed) |
3831 | phoneTile.onPressAndHold.disconnect(onPhoneLongPressed) |
3832 | } |
3833 | |
3834 | // Checks that components swicth to termination mode after (and only after) a long |
3835 | - // press happens on Calendar tile. |
3836 | + // press happens on Browser tile. |
3837 | function checkSwitchToTerminationModeAfterLongPress() { |
3838 | - compare(calendarTile.terminationModeEnabled, isCalendarLongPressed) |
3839 | - compare(phoneTile.terminationModeEnabled, isCalendarLongPressed) |
3840 | - compare(runningApplicationsGrid.terminationModeEnabled, isCalendarLongPressed) |
3841 | + compare(browserTile.terminationModeEnabled, isBrowserLongPressed) |
3842 | + compare(phoneTile.terminationModeEnabled, isBrowserLongPressed) |
3843 | + compare(runningApplicationsGrid.terminationModeEnabled, isBrowserLongPressed) |
3844 | |
3845 | - return isCalendarLongPressed && |
3846 | - calendarTile.terminationModeEnabled && |
3847 | + return isBrowserLongPressed && |
3848 | + browserTile.terminationModeEnabled && |
3849 | phoneTile.terminationModeEnabled && |
3850 | runningApplicationsGrid.terminationModeEnabled |
3851 | } |
3852 | @@ -185,12 +118,12 @@ |
3853 | // Checks that components swicth to activation mode after (and only after) a long |
3854 | // press happens on Phone tile. |
3855 | function checkSwitchToActivationModeAfterLongPress() { |
3856 | - compare(calendarTile.terminationModeEnabled, !isPhoneLongPressed) |
3857 | + compare(browserTile.terminationModeEnabled, !isPhoneLongPressed) |
3858 | compare(phoneTile.terminationModeEnabled, !isPhoneLongPressed) |
3859 | compare(runningApplicationsGrid.terminationModeEnabled, !isPhoneLongPressed) |
3860 | |
3861 | return isPhoneLongPressed && |
3862 | - !calendarTile.terminationModeEnabled && |
3863 | + !browserTile.terminationModeEnabled && |
3864 | !phoneTile.terminationModeEnabled && |
3865 | !runningApplicationsGrid.terminationModeEnabled |
3866 | } |
3867 | @@ -200,17 +133,17 @@ |
3868 | function test_clickTileNotClose() { |
3869 | runningApplicationsGrid.terminationModeEnabled = true |
3870 | |
3871 | - var calendarTile = findChild(runningApplicationsGrid, "runningAppTile Calendar") |
3872 | - verify(calendarTile != undefined) |
3873 | - |
3874 | - verify(fakeRunningAppsModel.contains("calendar")) |
3875 | - |
3876 | - mouseClick(calendarTile, calendarTile.width/2, calendarTile.height/2) |
3877 | - |
3878 | - verify(fakeRunningAppsModel.contains("calendar")) |
3879 | - |
3880 | - // The tile for the Calendar app should stay there |
3881 | - tryCompareFunction(checkCalendarTileExists, true) |
3882 | + var browserTile = findChild(runningApplicationsGrid, "runningAppTile Browser") |
3883 | + verify(browserTile != undefined) |
3884 | + |
3885 | + verify(ApplicationManager.findApplication("webbrowser-app") !== null) |
3886 | + |
3887 | + mouseClick(browserTile, browserTile.width/2, browserTile.height/2) |
3888 | + |
3889 | + verify(ApplicationManager.findApplication("webbrowser-app") !== null) |
3890 | + |
3891 | + // The tile for the Browser app should stay there |
3892 | + tryCompareFunction(checkBrowserTileExists, true) |
3893 | } |
3894 | |
3895 | // While in termination mode, clicking on a running application tile's close icon |
3896 | @@ -218,25 +151,25 @@ |
3897 | function test_clickCloseIconToTerminateApp() { |
3898 | runningApplicationsGrid.terminationModeEnabled = true |
3899 | |
3900 | - var calendarTile = findChild(runningApplicationsGrid, "runningAppTile Calendar") |
3901 | - var calendarTileCloseButton = findChild(runningApplicationsGrid, "closeIcon Calendar") |
3902 | - |
3903 | - verify(calendarTile != undefined) |
3904 | - verify(calendarTileCloseButton != undefined) |
3905 | - verify(fakeRunningAppsModel.contains("calendar")) |
3906 | - |
3907 | - mouseClick(calendarTileCloseButton, calendarTileCloseButton.width/2, calendarTileCloseButton.height/2) |
3908 | + var browserTile = findChild(runningApplicationsGrid, "runningAppTile Browser") |
3909 | + var browserTileCloseButton = findChild(runningApplicationsGrid, "closeIcon Browser") |
3910 | + |
3911 | + verify(browserTile != undefined) |
3912 | + verify(browserTileCloseButton != undefined) |
3913 | + verify(ApplicationManager.findApplication("webbrowser-app") !== 0) |
3914 | + |
3915 | + mouseClick(browserTileCloseButton, browserTileCloseButton.width/2, browserTileCloseButton.height/2) |
3916 | wait(0) // spin event loop to start any pending animation |
3917 | |
3918 | - verify(!fakeRunningAppsModel.contains("calendar")) |
3919 | + verify(ApplicationManager.findApplication("webbrowser-app") === null) |
3920 | |
3921 | - // The tile for the Calendar app should eventually vanish since the |
3922 | + // The tile for the Browser app should eventually vanish since the |
3923 | // application has been terminated. |
3924 | - tryCompareFunction(checkCalendarTileExists, false) |
3925 | + tryCompareFunction(checkBrowserTileExists, false) |
3926 | } |
3927 | |
3928 | - function checkCalendarTileExists() { |
3929 | - return findChild(runningApplicationsGrid, "runningAppTile Calendar") |
3930 | + function checkBrowserTileExists() { |
3931 | + return findChild(runningApplicationsGrid, "runningAppTile Browser") |
3932 | != undefined |
3933 | } |
3934 | |
3935 | @@ -245,8 +178,8 @@ |
3936 | function test_clickOutsideTilesDisablesTerminationMode() { |
3937 | runningApplicationsGrid.terminationModeEnabled = true |
3938 | |
3939 | - var calendarTile = findChild(runningApplicationsGrid, "runningAppTile Calendar") |
3940 | - verify(calendarTile != undefined) |
3941 | + var browserTile = findChild(runningApplicationsGrid, "runningAppTile Browser") |
3942 | + verify(browserTile != undefined) |
3943 | |
3944 | verify(runningApplicationsGrid.terminationModeEnabled); |
3945 | |
3946 | |
3947 | === added directory 'tests/qmltests/Stages' |
3948 | === added file 'tests/qmltests/Stages/tst_PhoneStage.qml' |
3949 | --- tests/qmltests/Stages/tst_PhoneStage.qml 1970-01-01 00:00:00 +0000 |
3950 | +++ tests/qmltests/Stages/tst_PhoneStage.qml 2014-03-25 15:08:15 +0000 |
3951 | @@ -0,0 +1,288 @@ |
3952 | +/* |
3953 | + * Copyright 2014 Canonical Ltd. |
3954 | + * |
3955 | + * This program is free software; you can redistribute it and/or modify |
3956 | + * it under the terms of the GNU General Public License as published by |
3957 | + * the Free Software Foundation; version 3. |
3958 | + * |
3959 | + * This program is distributed in the hope that it will be useful, |
3960 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
3961 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
3962 | + * GNU General Public License for more details. |
3963 | + * |
3964 | + * You should have received a copy of the GNU General Public License |
3965 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
3966 | + */ |
3967 | + |
3968 | +import QtQuick 2.0 |
3969 | +import QtTest 1.0 |
3970 | +import Unity.Test 0.1 as UT |
3971 | +import ".." |
3972 | +import "../../../qml/Stages" |
3973 | +import Ubuntu.Components 0.1 |
3974 | +import Unity.Application 0.1 |
3975 | + |
3976 | +Item { |
3977 | + width: units.gu(70) |
3978 | + height: units.gu(70) |
3979 | + |
3980 | + Rectangle { |
3981 | + |
3982 | + } |
3983 | + |
3984 | + PhoneStage { |
3985 | + id: phoneStage |
3986 | + anchors { fill: parent; rightMargin: units.gu(30) } |
3987 | + shown: true |
3988 | + dragAreaWidth: units.gu(2) |
3989 | + } |
3990 | + |
3991 | + Binding { |
3992 | + target: ApplicationManager |
3993 | + property: "rightMargin" |
3994 | + value: phoneStage.anchors.rightMargin |
3995 | + } |
3996 | + |
3997 | + Rectangle { |
3998 | + anchors { fill: parent; leftMargin: phoneStage.width } |
3999 | +// color: "blue" |
4000 | + |
4001 | + Column { |
4002 | + anchors { left: parent.left; right: parent.right; top: parent.top; margins: units.gu(1) } |
4003 | + spacing: units.gu(1) |
4004 | + Button { |
4005 | + anchors { left: parent.left; right: parent.right } |
4006 | + text: "Add App" |
4007 | + onClicked: { |
4008 | + testCase.addApps(); |
4009 | + } |
4010 | + } |
4011 | + Button { |
4012 | + anchors { left: parent.left; right: parent.right } |
4013 | + text: "Add App" |
4014 | + } |
4015 | + } |
4016 | + } |
4017 | + |
4018 | + UT.UnityTestCase { |
4019 | + id: testCase |
4020 | + name: "PhoneStage" |
4021 | + when: windowShown |
4022 | + |
4023 | + function addApps(count) { |
4024 | + if (count == undefined) count = 1; |
4025 | + for (var i = 0; i < count; i++) { |
4026 | + var app = ApplicationManager.startApplication(ApplicationManager.availableApplications()[ApplicationManager.count]) |
4027 | + tryCompare(app, "state", ApplicationInfoInterface.Running) |
4028 | + // Fixme: Right now there is a timeout in the PhoneStage that displays a white splash |
4029 | + // screen rectangle when an app starts. This is because we don't yet have a way of |
4030 | + // knowing when an app has finished launching. That workaround and this wait() should |
4031 | + // go away at some point and the app's state only changing to Running when ready for real. |
4032 | +// wait(1000) |
4033 | + waitForRendering(phoneStage) |
4034 | + } |
4035 | + } |
4036 | + |
4037 | + function goToSpread() { |
4038 | + var spreadView = findChild(phoneStage, "spreadView"); |
4039 | + |
4040 | + var startX = phoneStage.width; |
4041 | + var startY = phoneStage.height / 2; |
4042 | + var endY = startY; |
4043 | + var endX = units.gu(2); |
4044 | + |
4045 | + touchFlick(phoneStage, startX, startY, endX, endY, |
4046 | + true /* beginTouch */, true /* endTouch */, units.gu(10), 50); |
4047 | + } |
4048 | + |
4049 | + function test_shortFlick() { |
4050 | + addApps(2) |
4051 | + var startX = phoneStage.width - units.gu(1); |
4052 | + var startY = phoneStage.height / 2; |
4053 | + var endX = phoneStage.width / 2; |
4054 | + var endY = startY; |
4055 | + |
4056 | + var activeApp = ApplicationManager.get(0); |
4057 | + var inactiveApp = ApplicationManager.get(1); |
4058 | + |
4059 | + touchFlick(phoneStage, startX, startY, endX, endY, |
4060 | + true /* beginTouch */, true /* endTouch */, units.gu(10), 50); |
4061 | + |
4062 | + tryCompare(ApplicationManager, "focusedApplicationId", inactiveApp.appId) |
4063 | + |
4064 | + touchFlick(phoneStage, startX, startY, endX, endY, |
4065 | + true /* beginTouch */, true /* endTouch */, units.gu(10), 50); |
4066 | + |
4067 | + tryCompare(ApplicationManager, "focusedApplicationId", activeApp.appId) |
4068 | + |
4069 | + tryCompare(phoneStage, "painting", false); |
4070 | + } |
4071 | + |
4072 | + function test_enterSpread_data() { |
4073 | + return [ |
4074 | + {tag: "<position1 (linear movement)", positionMarker: "positionMarker1", linear: true, offset: -1, endPhase: 0, targetPhase: 0, newFocusedIndex: 1 }, |
4075 | + {tag: "<position1 (non-linear movement)", positionMarker: "positionMarker1", linear: false, offset: -1, endPhase: 0, targetPhase: 0, newFocusedIndex: 0 }, |
4076 | + {tag: ">position1", positionMarker: "positionMarker1", linear: true, offset: +1, endPhase: 0, targetPhase: 0, newFocusedIndex: 1 }, |
4077 | + {tag: "<position2 (linear)", positionMarker: "positionMarker2", linear: true, offset: -1, endPhase: 0, targetPhase: 0, newFocusedIndex: 1 }, |
4078 | + {tag: "<position2 (non-linear)", positionMarker: "positionMarker2", linear: false, offset: -1, endPhase: 0, targetPhase: 0, newFocusedIndex: 1 }, |
4079 | + {tag: ">position2", positionMarker: "positionMarker2", linear: true, offset: +1, endPhase: 1, targetPhase: 0, newFocusedIndex: 1 }, |
4080 | + {tag: "<position3", positionMarker: "positionMarker3", linear: true, offset: -1, endPhase: 1, targetPhase: 0, newFocusedIndex: 1 }, |
4081 | + {tag: ">position3", positionMarker: "positionMarker3", linear: true, offset: +1, endPhase: 2, targetPhase: 2, newFocusedIndex: 2 }, |
4082 | + ]; |
4083 | + } |
4084 | + |
4085 | + function test_enterSpread(data) { |
4086 | + addApps(5) |
4087 | + |
4088 | + var spreadView = findChild(phoneStage, "spreadView"); |
4089 | + |
4090 | + var startX = phoneStage.width; |
4091 | + var startY = phoneStage.height / 2; |
4092 | + var endY = startY; |
4093 | + var endX = spreadView.width - (spreadView.width * spreadView[data.positionMarker]) - data.offset - phoneStage.dragAreaWidth; |
4094 | + |
4095 | + var oldFocusedApp = ApplicationManager.get(0); |
4096 | + var newFocusedApp = ApplicationManager.get(data.newFocusedIndex); |
4097 | + |
4098 | + touchFlick(phoneStage, startX, startY, endX, endY, |
4099 | + true /* beginTouch */, false /* endTouch */, units.gu(10), 50); |
4100 | + |
4101 | + tryCompare(spreadView, "phase", data.endPhase) |
4102 | + |
4103 | + if (!data.linear) { |
4104 | + touchFlick(phoneStage, endX, endY, endX + units.gu(.5), endY, |
4105 | + false /* beginTouch */, false /* endTouch */, units.gu(10), 50); |
4106 | + touchFlick(phoneStage, endY + units.gu(.5), endY, endX, endY, |
4107 | + false /* beginTouch */, false /* endTouch */, units.gu(10), 50); |
4108 | + } |
4109 | + |
4110 | + touchRelease(phoneStage, endX, endY); |
4111 | + |
4112 | + tryCompare(spreadView, "phase", data.targetPhase) |
4113 | + |
4114 | + if (data.targetPhase == 2) { |
4115 | + var app2 = findChild(spreadView, "appDelegate2"); |
4116 | + mouseClick(app2, units.gu(1), units.gu(1)); |
4117 | + } |
4118 | + |
4119 | + tryCompare(phoneStage, "painting", false); |
4120 | + tryCompare(ApplicationManager, "focusedApplicationId", newFocusedApp.appId); |
4121 | + } |
4122 | + |
4123 | + function test_selectAppFromSpread_data() { |
4124 | + var appsToTest = 6; |
4125 | + var apps = new Array(); |
4126 | + for (var i = 0; i < appsToTest; i++) { |
4127 | + var item = new Object(); |
4128 | + item.tag = "App " + i; |
4129 | + item.index = i; |
4130 | + item.total = appsToTest; |
4131 | + apps.push(item) |
4132 | + } |
4133 | + return apps; |
4134 | + } |
4135 | + |
4136 | + function test_selectAppFromSpread(data) { |
4137 | + addApps(data.total) |
4138 | + |
4139 | + var spreadView = findChild(phoneStage, "spreadView"); |
4140 | + |
4141 | + goToSpread(); |
4142 | + |
4143 | + tryCompare(spreadView, "phase", 2); |
4144 | + |
4145 | + var tile = findChild(spreadView, "appDelegate" + data.index); |
4146 | + var appId = ApplicationManager.get(data.index).appId; |
4147 | + |
4148 | + if (tile.mapToItem(spreadView).x > spreadView.width) { |
4149 | + // Item is not visible... Need to flick the spread |
4150 | + var startX = phoneStage.width - units.gu(1); |
4151 | + var startY = phoneStage.height / 2; |
4152 | + var endY = startY; |
4153 | + var endX = units.gu(2); |
4154 | + touchFlick(phoneStage, startX, startY, endX, endY, true, true, units.gu(10), 50) |
4155 | + tryCompare(spreadView, "flicking", false); |
4156 | + tryCompare(spreadView, "moving", false); |
4157 | +// waitForRendering(phoneStage); |
4158 | + } |
4159 | + |
4160 | + console.log("clicking app", data.index, "(", appId, ")") |
4161 | + mouseClick(spreadView, tile.mapToItem(spreadView).x + units.gu(1), spreadView.height / 2) |
4162 | + tryCompare(ApplicationManager, "focusedApplicationId", appId); |
4163 | + tryCompare(spreadView, "phase", 0); |
4164 | + } |
4165 | + |
4166 | + function test_animateAppStartup() { |
4167 | + compare(phoneStage.painting, false); |
4168 | + addApps(2); |
4169 | + tryCompare(phoneStage, "painting", true); |
4170 | + tryCompare(phoneStage, "painting", false); |
4171 | + addApps(1); |
4172 | + tryCompare(phoneStage, "painting", true); |
4173 | + tryCompare(phoneStage, "painting", false); |
4174 | + } |
4175 | + |
4176 | + function test_select_data() { |
4177 | + return [ |
4178 | + { tag: "0", index: 0 }, |
4179 | + { tag: "2", index: 2 }, |
4180 | + { tag: "4", index: 4 }, |
4181 | + ] |
4182 | + } |
4183 | + |
4184 | + function test_select(data) { |
4185 | + addApps(5); |
4186 | + |
4187 | + var spreadView = findChild(phoneStage, "spreadView"); |
4188 | + var selectedApp = ApplicationManager.get(data.index); |
4189 | + |
4190 | + goToSpread(); |
4191 | + |
4192 | + phoneStage.select(selectedApp.appId); |
4193 | + |
4194 | + tryCompare(phoneStage, "painting", false); |
4195 | + compare(ApplicationManager.focusedApplicationId, selectedApp.appId); |
4196 | + } |
4197 | + |
4198 | + function test_fullscreenMode() { |
4199 | + var fullscreenApp = null; |
4200 | + var normalApp = null; |
4201 | + |
4202 | + for (var i = 0; i < 5; i++) { |
4203 | + addApps(1); |
4204 | + var newApp = ApplicationManager.get(0); |
4205 | + tryCompare(phoneStage, "fullscreen", newApp.fullscreen); |
4206 | + if (newApp.fullscreen && fullscreenApp == null) { |
4207 | + fullscreenApp = newApp; |
4208 | + } else if (!newApp.fullscreen && normalApp == null){ |
4209 | + normalApp = newApp; |
4210 | + } |
4211 | + } |
4212 | + verify(fullscreenApp != null); // Can't continue the test without having a fullscreen app |
4213 | + verify(normalApp != null); // Can't continue the test without having a non-fullscreen app |
4214 | + |
4215 | + // Select a normal app |
4216 | + goToSpread(); |
4217 | + phoneStage.select(normalApp.appId); |
4218 | + tryCompare(phoneStage, "fullscreen", false); |
4219 | + |
4220 | + // Select a fullscreen app |
4221 | + goToSpread(); |
4222 | + phoneStage.select(fullscreenApp.appId); |
4223 | + tryCompare(phoneStage, "fullscreen", true); |
4224 | + |
4225 | + // Select a normal app |
4226 | + goToSpread(); |
4227 | + phoneStage.select(normalApp.appId); |
4228 | + tryCompare(phoneStage, "fullscreen", false); |
4229 | + } |
4230 | + |
4231 | + function cleanup() { |
4232 | + while (ApplicationManager.count > 0) { |
4233 | + var oldCount = ApplicationManager.count; |
4234 | + ApplicationManager.stopApplication(ApplicationManager.get(0).appId) |
4235 | + tryCompare(ApplicationManager, "count", oldCount - 1) |
4236 | + } |
4237 | + } |
4238 | + } |
4239 | +} |
4240 | |
4241 | === modified file 'tests/qmltests/tst_Shell.qml' |
4242 | --- tests/qmltests/tst_Shell.qml 2014-03-19 10:48:06 +0000 |
4243 | +++ tests/qmltests/tst_Shell.qml 2014-03-25 15:08:15 +0000 |
4244 | @@ -117,6 +117,7 @@ |
4245 | while (apps.count > 0) { |
4246 | ApplicationManager.stopApplication(apps.get(0).appId); |
4247 | } |
4248 | + compare(ApplicationManager.count, 0) |
4249 | } |
4250 | |
4251 | /* |
4252 | @@ -187,26 +188,34 @@ |
4253 | tapOnAppIconInLauncher(); |
4254 | waitUntilApplicationWindowIsFullyVisible(); |
4255 | |
4256 | - var mainApp = ApplicationManager.focusedApplicationId; |
4257 | - verify(mainApp != ""); |
4258 | + var mainAppId = ApplicationManager.focusedApplicationId; |
4259 | + verify(mainAppId != ""); |
4260 | + var mainApp = ApplicationManager.findApplication(mainAppId); |
4261 | + verify(mainApp); |
4262 | + tryCompare(mainApp.state, ApplicationInfo.Running); |
4263 | |
4264 | // Try to suspend while proximity is engaged... |
4265 | Powerd.displayPowerStateChange(Powerd.Off, Powerd.UseProximity); |
4266 | tryCompare(greeter, "showProgress", 0); |
4267 | |
4268 | // Now really suspend |
4269 | + print("suspending") |
4270 | Powerd.displayPowerStateChange(Powerd.Off, 0); |
4271 | + print("done suspending") |
4272 | tryCompare(greeter, "showProgress", 1); |
4273 | - tryCompare(ApplicationManager, "focusedApplicationId", ""); |
4274 | + |
4275 | + tryCompare(ApplicationManager, "suspended", true); |
4276 | + compare(mainApp.state, ApplicationInfo.Suspended); |
4277 | |
4278 | // And wake up |
4279 | Powerd.displayPowerStateChange(Powerd.On, 0); |
4280 | - tryCompare(ApplicationManager, "focusedApplicationId", ""); |
4281 | tryCompare(greeter, "showProgress", 1); |
4282 | |
4283 | // Swipe away greeter to focus app |
4284 | swipeAwayGreeter(); |
4285 | - tryCompare(ApplicationManager, "focusedApplicationId", mainApp); |
4286 | + tryCompare(ApplicationManager, "suspended", false); |
4287 | + compare(mainApp.state, ApplicationInfo.Running); |
4288 | + tryCompare(ApplicationManager, "focusedApplicationId", mainAppId); |
4289 | } |
4290 | |
4291 | function swipeAwayGreeter() { |
4292 | @@ -239,7 +248,7 @@ |
4293 | tryCompare(dash, "opacity", 1.0); |
4294 | |
4295 | touchFlick(shell, touchX, touchY, shell.width * 0.1, touchY, |
4296 | - true /* beginTouch */, false /* endTouch */); |
4297 | + true /* beginTouch */, false /* endTouch */, units.gu(10), 50); |
4298 | |
4299 | // check that Dash has been scaled down and had its opacity reduced |
4300 | tryCompareFunction(function() { return dash.contentScale <= 0.9; }, true); |
4301 | @@ -270,7 +279,7 @@ |
4302 | tryCompare(dash, "opacity", 1.0); |
4303 | |
4304 | touchFlick(shell, touchX, touchY, shell.width * 0.1, touchY, |
4305 | - true /* beginTouch */, false /* endTouch */); |
4306 | + true /* beginTouch */, false /* endTouch */, units.gu(10), 50); |
4307 | |
4308 | // check that Dash has been scaled down and had its opacity reduced |
4309 | tryCompareFunction(function() { return dash.contentScale <= 0.9; }, true); |
4310 | @@ -486,7 +495,6 @@ |
4311 | } |
4312 | |
4313 | function test_DashShown(data) { |
4314 | - |
4315 | if (data.greeter) { |
4316 | // Swipe the greeter in |
4317 | var greeter = findChild(shell, "greeter"); |
FAILED: Continuous integration, rev:661 /code.launchpad .net/~mzanetti/ unity8/ right-edge- 2/+merge/ 204798/ +edit-commit- message
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https:/
http:// jenkins. qa.ubuntu. com/job/ unity8- ci/2423/ jenkins. qa.ubuntu. com/job/ generic- mediumtests- trusty/ 3644/console jenkins. qa.ubuntu. com/job/ generic- mediumtests- trusty- touch/3249/ console jenkins. qa.ubuntu. com/job/ unity-phablet- qmluitests- trusty/ 1293/console jenkins. qa.ubuntu. com/job/ unity8- trusty- amd64-ci/ 944/console jenkins. qa.ubuntu. com/job/ unity8- trusty- armhf-ci/ 948/console jenkins. qa.ubuntu. com/job/ unity8- trusty- i386-ci/ 944/console jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- trusty- amd64/3648/ console jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- trusty- armhf/3251/ console
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/unity8- ci/2423/ rebuild
http://