Merge lp:~mzanetti/unity8/appdrawer into lp:unity8

Proposed by Michael Zanetti
Status: Merged
Approved by: Lukáš Tinkl
Approved revision: 2715
Merged at revision: 2731
Proposed branch: lp:~mzanetti/unity8/appdrawer
Merge into: lp:unity8
Prerequisite: lp:~ci-train-bot/unity8/unity8-ubuntu-zesty-2202
Diff against target: 2932 lines (+1624/-416)
49 files modified
data/com.canonical.Unity8.gschema.xml (+2/-2)
debian/control (+3/-1)
plugins/Greeter/Unity/Launcher/CMakeLists.txt (+1/-1)
plugins/Greeter/Unity/Launcher/launcheritem.cpp (+13/-0)
plugins/Greeter/Unity/Launcher/launcheritem.h (+3/-0)
plugins/Unity/Launcher/CMakeLists.txt (+4/-1)
plugins/Unity/Launcher/appdrawermodel.cpp (+62/-0)
plugins/Unity/Launcher/appdrawermodel.h (+33/-0)
plugins/Unity/Launcher/launcheritem.cpp (+13/-0)
plugins/Unity/Launcher/launcheritem.h (+4/-0)
plugins/Unity/Launcher/launchermodel.cpp (+6/-37)
plugins/Unity/Launcher/launchermodel.h (+0/-14)
plugins/Unity/Launcher/plugin.cpp (+2/-1)
plugins/Unity/Launcher/ualwrapper.cpp (+73/-0)
plugins/Unity/Launcher/ualwrapper.h (+35/-0)
plugins/Utils/CMakeLists.txt (+4/-0)
plugins/Utils/appdrawerproxymodel.cpp (+189/-0)
plugins/Utils/appdrawerproxymodel.h (+87/-0)
plugins/Utils/plugin.cpp (+2/-0)
qml/Components/KeyboardShortcutsOverlay.qml (+13/-0)
qml/Launcher/BackgroundBlur.qml (+81/-0)
qml/Launcher/Drawer.qml (+306/-0)
qml/Launcher/DrawerGridView.qml (+47/-0)
qml/Launcher/DrawerListView.qml (+32/-0)
qml/Launcher/Launcher.qml (+150/-30)
qml/Launcher/MoreAppsHeader.qml (+46/-0)
qml/Shell.qml (+10/-34)
qml/Stage/Stage.qml (+3/-6)
qml/Stage/StageMaths.qml (+2/-7)
qml/Tutorial/TutorialLeftLong.qml (+1/-1)
tests/mocks/Unity/Launcher/CMakeLists.txt (+5/-1)
tests/mocks/Unity/Launcher/MockAppDrawerModel.cpp (+75/-0)
tests/mocks/Unity/Launcher/MockAppDrawerModel.h (+32/-0)
tests/mocks/Unity/Launcher/MockLauncherItem.cpp (+13/-0)
tests/mocks/Unity/Launcher/MockLauncherItem.h (+6/-0)
tests/mocks/Unity/Launcher/MockLauncherModel.cpp (+3/-0)
tests/mocks/Unity/Launcher/plugin.cpp (+4/-0)
tests/mocks/Utils/CMakeLists.txt (+4/-0)
tests/mocks/Utils/plugin.cpp (+2/-0)
tests/plugins/Greeter/Unity/Launcher/CMakeLists.txt (+1/-1)
tests/plugins/Unity/Launcher/CMakeLists.txt (+2/-1)
tests/qmltests/CMakeLists.txt (+1/-0)
tests/qmltests/Dash/tst_DashShell.qml (+0/-29)
tests/qmltests/Launcher/tst_Drawer.qml (+245/-0)
tests/qmltests/Launcher/tst_Launcher.qml (+1/-1)
tests/qmltests/Stage/tst_PhoneStage.qml (+0/-26)
tests/qmltests/tst_OrientedShell.qml (+1/-13)
tests/qmltests/tst_Shell.qml (+2/-143)
tests/qmltests/tst_ShellWithPin.qml (+0/-66)
To merge this branch: bzr merge lp:~mzanetti/unity8/appdrawer
Reviewer Review Type Date Requested Status
Lukáš Tinkl (community) Approve
Unity8 CI Bot continuous-integration Approve
Ubuntu Unity PS integration team Pending
Review via email: mp+312141@code.launchpad.net

This proposal supersedes a proposal from 2016-11-04.

Commit message

Add the ApplicationDrawer

Description of the change

Prereq-archive: ppa:ci-train-ppa-service/2150

 * Are there any related MPs required for this MP to build/function as expected? Please list.

https://code.launchpad.net/~mzanetti/unity-api/appdrawermodelinterface/+merge/310057

 * Did you perform an exploratory manual test run of your code change and any related functionality?

yes

 * 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?

pending

To post a comment you must log in.
Revision history for this message
Lukáš Tinkl (lukas-kde) wrote : Posted in a previous version of this proposal

Some comments inline plus one question (mainly for design):

Shouldn't the "A..Z" header be omitted for now, until we also have the other one (recent apps)?

review: Needs Information
Revision history for this message
Lukáš Tinkl (lukas-kde) wrote : Posted in a previous version of this proposal

Some speed improvements for ualwrapper: https://pastebin.kde.org/pby8twga2

review: Needs Fixing
Revision history for this message
Lukáš Tinkl (lukas-kde) wrote : Posted in a previous version of this proposal

And a minor one for the proxy model: https://pastebin.kde.org/p7gufb8w2

review: Needs Fixing
Revision history for this message
Lukáš Tinkl (lukas-kde) wrote : Posted in a previous version of this proposal

When the shell/session starts, I can clearly see the app drawer on screen for like a 1 second, and then sliding to the left to hide.

review: Needs Fixing
Revision history for this message
Lukáš Tinkl (lukas-kde) wrote : Posted in a previous version of this proposal

If there are windows underneath the open drawer, the cursor changes shape as to resize them -> need some hover event eater

review: Needs Fixing
Revision history for this message
Lukáš Tinkl (lukas-kde) wrote : Posted in a previous version of this proposal

I see unity7 control center modules in the list of apps, those should be hidden imo?

review: Needs Information
Revision history for this message
Lukáš Tinkl (lukas-kde) wrote : Posted in a previous version of this proposal

When the app drawer is open using the shortcut for text input, the previously entered text isn't preselected (so you cannot start directly overwriting the last text).

review: Needs Fixing
Revision history for this message
Lukáš Tinkl (lukas-kde) wrote : Posted in a previous version of this proposal

The shortcut alone (Super+A) is also imo debatable (up for a design decision), now that the show-dash functionality is gone, I think the Super key alone should be used for opening the drawer if the launcher is already on the screen, wdyt?

review: Needs Information
Revision history for this message
Lukáš Tinkl (lukas-kde) wrote : Posted in a previous version of this proposal

The new classes lack copyright headers

review: Needs Fixing
Revision history for this message
Michael Zanetti (mzanetti) wrote : Posted in a previous version of this proposal

All the "Needs fixing" should be fixed now, except one inline comment where I replied to and

> And a minor one for the proxy model: https://pastebin.kde.org/p7gufb8w2

This doesn't compile.

For the "Needs information" ones, yes, I do agree with you, however they are either to be fixed in u-a-l, or design has no answer yet.

Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal

FAILED: Continuous integration, rev:2702
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2570/
Executed test runs:
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build/3383
    UNSTABLE: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=vivid+overlay,testname=qmluitests.sh/1944
    UNSTABLE: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=xenial+overlay,testname=qmluitests.sh/1944
    UNSTABLE: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=zesty,testname=qmluitests.sh/1944
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-0-fetch/3411
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=vivid+overlay/3262
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=vivid+overlay/3262/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/3262
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/3262/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/3262
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/3262/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=vivid+overlay/3262
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=vivid+overlay/3262/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/3262
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/3262/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/3262
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/3262/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=vivid+overlay/3262
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=vivid+overlay/3262/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/3262
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/3262/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/3262
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/3262/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2570/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal

FAILED: Continuous integration, rev:2704
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2574/
Executed test runs:
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build/3388
    UNSTABLE: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=vivid+overlay,testname=qmluitests.sh/1948
    UNSTABLE: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=xenial+overlay,testname=qmluitests.sh/1948
    UNSTABLE: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=zesty,testname=qmluitests.sh/1948
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-0-fetch/3416
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=vivid+overlay/3267
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=vivid+overlay/3267/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/3267
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/3267/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/3267
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/3267/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=vivid+overlay/3267
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=vivid+overlay/3267/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/3267
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/3267/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/3267
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/3267/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=vivid+overlay/3267
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=vivid+overlay/3267/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/3267
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/3267/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/3267
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/3267/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2574/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal

FAILED: Continuous integration, rev:2706
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2577/
Executed test runs:
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build/3392
    UNSTABLE: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=vivid+overlay,testname=qmluitests.sh/1951
    UNSTABLE: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=xenial+overlay,testname=qmluitests.sh/1951
    UNSTABLE: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=zesty,testname=qmluitests.sh/1951
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-0-fetch/3420
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=vivid+overlay/3271
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=vivid+overlay/3271/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/3271
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/3271/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/3271
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/3271/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=vivid+overlay/3271
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=vivid+overlay/3271/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/3271
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/3271/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/3271
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/3271/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=vivid+overlay/3271
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=vivid+overlay/3271/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/3271
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/3271/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/3271
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/3271/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2577/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal

FAILED: Continuous integration, rev:2710
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2585/
Executed test runs:
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build/3400
    UNSTABLE: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=vivid+overlay,testname=qmluitests.sh/1957
    UNSTABLE: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=xenial+overlay,testname=qmluitests.sh/1957
    UNSTABLE: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=zesty,testname=qmluitests.sh/1957
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-0-fetch/3428
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=vivid+overlay/3279
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=vivid+overlay/3279/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/3279
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/3279/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/3279
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/3279/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=vivid+overlay/3279
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=vivid+overlay/3279/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/3279
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/3279/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/3279
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/3279/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=vivid+overlay/3279
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=vivid+overlay/3279/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/3279
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/3279/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/3279
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/3279/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2585/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Lukáš Tinkl (lukas-kde) wrote : Posted in a previous version of this proposal

The CI failures on xenial/zesty need fixing:

/tmp/autopkgtest.CvSNaq/build.pNd/unity8-8.15+17.04.20161116.1+fetch3428bzr2710/qml/Launcher/Drawer.qml:22,1: module "Qt.labs.settings" is not installed

review: Needs Fixing
Revision history for this message
Omer Akram (om26er) wrote : Posted in a previous version of this proposal

What is the future of unity8-dash after this change? I am coming from a scenario where the only scope that I have is the App scope, so if we have an app drawer, does it mean there will be an empty desktop when drawer is closed ?

Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal

FAILED: Continuous integration, rev:2711
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2591/
Executed test runs:
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build/3408
    UNSTABLE: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=vivid+overlay,testname=qmluitests.sh/1961
    UNSTABLE: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=xenial+overlay,testname=qmluitests.sh/1961
    UNSTABLE: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=zesty,testname=qmluitests.sh/1961
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-0-fetch/3436
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=vivid+overlay/3287
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=vivid+overlay/3287/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/3287
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/3287/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/3287
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/3287/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=vivid+overlay/3287
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=vivid+overlay/3287/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/3287
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/3287/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/3287
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/3287/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=vivid+overlay/3287
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=vivid+overlay/3287/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/3287
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/3287/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/3287
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/3287/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2591/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Lukáš Tinkl (lukas-kde) wrote : Posted in a previous version of this proposal

OK, all the issues I mentioned are fixed, no more objections from me

* Did you perform an exploratory manual test run of the code change and any related functionality?

Yes!

* Did CI run pass? If not, please explain why.

Not yet, will wait with top approval

review: Approve
Revision history for this message
Michael Zanetti (mzanetti) wrote : Posted in a previous version of this proposal

> What is the future of unity8-dash after this change? I am coming from a
> scenario where the only scope that I have is the App scope, so if we have an
> app drawer, does it mean there will be an empty desktop when drawer is closed
> ?

The drawer will definitely replace the apps scope. What exactly that will mean for the dash in general, I don't know yet. However, in order for the apps scope to be dropped, we first also need a replacement for the app store scope. So for now, they will coexist.

Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal

FAILED: Continuous integration, rev:2712
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2600/
Executed test runs:
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build/3422
    UNSTABLE: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=xenial+overlay,testname=qmluitests.sh/1966
    UNSTABLE: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=zesty,testname=qmluitests.sh/1966
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-0-fetch/3450
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/3297
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/3297/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/3297
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/3297/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/3297
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/3297/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/3297
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/3297/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/3297
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/3297/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/3297
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/3297/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2600/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Lukáš Tinkl (lukas-kde) wrote : Posted in a previous version of this proposal

The 3 CI failures seem related, needs fixing

review: Needs Fixing
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote : Posted in a previous version of this proposal

PASSED: Continuous integration, rev:2713
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2604/
Executed test runs:
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build/3426
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=xenial+overlay,testname=qmluitests.sh/1967
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=zesty,testname=qmluitests.sh/1967
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-0-fetch/3454
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/3301
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/3301/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/3301
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/3301/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/3301
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/3301/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/3301
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/3301/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/3301
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/3301/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/3301
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/3301/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2604/rebuild

review: Approve (continuous-integration)
Revision history for this message
Lukáš Tinkl (lukas-kde) wrote : Posted in a previous version of this proposal

CI is green, everything's fine

review: Approve
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Unity8 CI Bot (unity8-ci-bot) wrote :

PASSED: Continuous integration, rev:2715
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2606/
Executed test runs:
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build/3429
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=xenial+overlay,testname=qmluitests.sh/1969
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/test-0-autopkgtest/label=amd64,release=zesty,testname=qmluitests.sh/1969
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-0-fetch/3457
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/3304
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=xenial+overlay/3304/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/3304
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=amd64,release=zesty/3304/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/3304
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=xenial+overlay/3304/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/3304
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=armhf,release=zesty/3304/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/3304
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=xenial+overlay/3304/artifact/output/*zip*/output.zip
    SUCCESS: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/3304
        deb: https://unity8-jenkins.ubuntu.com/job/build-2-binpkg/arch=i386,release=zesty/3304/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://unity8-jenkins.ubuntu.com/job/lp-unity8-ci/2606/rebuild

review: Approve (continuous-integration)
Revision history for this message
Lukáš Tinkl (lukas-kde) wrote :

Re-approving after having been resubmitted; CI is also back to green

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'data/com.canonical.Unity8.gschema.xml'
2--- data/com.canonical.Unity8.gschema.xml 2016-11-16 05:54:50 +0000
3+++ data/com.canonical.Unity8.gschema.xml 2016-12-07 18:01:28 +0000
4@@ -12,7 +12,7 @@
5 <description>The usage mode chosen will affect the Window Management behaviour.</description>
6 </key>
7 <key type="y" name="edge-barrier-sensitivity">
8- <default>35</default>
9+ <default>50</default>
10 <range min="1" max="100"/>
11 <summary>Sensitivity of screen edge barriers for the mouse pointer.</summary>
12 <description>Some UI actions like revealing the launcher or the applications spread are triggered by pushing the mouse pointer against a screen edge. This key defines how much you have to push in order to trigger the associated action.</description>
13@@ -23,7 +23,7 @@
14 <description>How much you have to push (in grid units)the mouse against an edge barrier when sensibility is 100.</description>
15 </key>
16 <key type="u" name="edge-barrier-max-push">
17- <default>60</default>
18+ <default>120</default>
19 <summary>Maximum push needed to overcome edge barrier</summary>
20 <description>How much you have to push (in grid units) the mouse against an edge barrier when sensibility is 1.</description>
21 </key>
22
23=== modified file 'debian/control'
24--- debian/control 2016-11-29 09:40:16 +0000
25+++ debian/control 2016-12-07 18:01:28 +0000
26@@ -38,7 +38,7 @@
27 libubuntugestures5-private-dev (>= 1.3.2030),
28 libudev-dev,
29 libudm-common-dev,
30- libunity-api-dev (>= 7.120),
31+ libunity-api-dev (>= 7.121),
32 libusermetricsoutput1-dev,
33 # Need those X11 libs touch emulation from mouse events in manual QML tests on a X11 desktop
34 libx11-dev[!arm64 !armhf],
35@@ -49,6 +49,7 @@
36 python3-all:any,
37 python3-setuptools,
38 qml-module-qt-labs-folderlistmodel,
39+ qml-module-qt-labs-settings,
40 qml-module-qtqml-statemachine,
41 qml-module-qtmultimedia (>= 5.4.1-1ubuntu19~overlay2),
42 qml-module-qtquick-layouts,
43@@ -122,6 +123,7 @@
44 qmenumodel-qml (>= 0.2.10),
45 qml-module-biometryd,
46 qml-module-qt-labs-folderlistmodel,
47+ qml-module-qt-labs-settings,
48 qml-module-qtqml-statemachine,
49 qml-module-qtquick-xmllistmodel,
50 qml-module-qtsysteminfo,
51
52=== modified file 'plugins/Greeter/Unity/Launcher/CMakeLists.txt'
53--- plugins/Greeter/Unity/Launcher/CMakeLists.txt 2016-10-28 12:08:59 +0000
54+++ plugins/Greeter/Unity/Launcher/CMakeLists.txt 2016-12-07 18:01:28 +0000
55@@ -1,4 +1,4 @@
56-pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=10)
57+pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=11)
58 pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)
59
60 add_definitions(-DSM_BUSNAME=systemBus)
61
62=== modified file 'plugins/Greeter/Unity/Launcher/launcheritem.cpp'
63--- plugins/Greeter/Unity/Launcher/launcheritem.cpp 2016-05-10 16:23:34 +0000
64+++ plugins/Greeter/Unity/Launcher/launcheritem.cpp 2016-12-07 18:01:28 +0000
65@@ -76,6 +76,19 @@
66 }
67 }
68
69+QStringList LauncherItem::keywords() const
70+{
71+ return m_keywords;
72+}
73+
74+void LauncherItem::setKeywords(const QStringList &keywords)
75+{
76+ if (m_keywords != keywords) {
77+ m_keywords = keywords;
78+ Q_EMIT keywordsChanged(keywords);
79+ }
80+}
81+
82 bool LauncherItem::pinned() const
83 {
84 return m_pinned;
85
86=== modified file 'plugins/Greeter/Unity/Launcher/launcheritem.h'
87--- plugins/Greeter/Unity/Launcher/launcheritem.h 2016-05-10 15:51:00 +0000
88+++ plugins/Greeter/Unity/Launcher/launcheritem.h 2016-12-07 18:01:28 +0000
89@@ -34,6 +34,7 @@
90 QString appId() const override;
91 QString name() const override;
92 QString icon() const override;
93+ QStringList keywords() const override;
94 bool pinned() const override;
95 bool running() const override;
96 bool recent() const override;
97@@ -49,6 +50,7 @@
98 private:
99 void setName(const QString &name);
100 void setIcon(const QString &icon);
101+ void setKeywords(const QStringList &keywords);
102 void setPinned(bool pinned);
103 void setRunning(bool running);
104 void setRecent(bool recent);
105@@ -63,6 +65,7 @@
106 QString m_appId;
107 QString m_name;
108 QString m_icon;
109+ QStringList m_keywords;
110 bool m_pinned;
111 bool m_running;
112 bool m_recent;
113
114=== modified file 'plugins/Unity/Launcher/CMakeLists.txt'
115--- plugins/Unity/Launcher/CMakeLists.txt 2016-10-28 12:08:59 +0000
116+++ plugins/Unity/Launcher/CMakeLists.txt 2016-12-07 18:01:28 +0000
117@@ -1,4 +1,4 @@
118-pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=10)
119+pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=11)
120 pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)
121
122 add_definitions(-DSM_BUSNAME=systemBus)
123@@ -25,6 +25,8 @@
124 dbusinterface.cpp
125 gsettings.cpp
126 asadapter.cpp
127+ appdrawermodel.cpp
128+ ualwrapper.cpp
129 ${CMAKE_SOURCE_DIR}/plugins/AccountsService/AccountsServiceDBusAdaptor.cpp
130 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationManagerInterface.h
131 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationInfoInterface.h
132@@ -32,6 +34,7 @@
133 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherItemInterface.h
134 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherModelInterface.h
135 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/QuickListModelInterface.h
136+ ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/AppDrawerModelInterface.h
137 )
138
139 add_library(UnityLauncher-qml MODULE
140
141=== added file 'plugins/Unity/Launcher/appdrawermodel.cpp'
142--- plugins/Unity/Launcher/appdrawermodel.cpp 1970-01-01 00:00:00 +0000
143+++ plugins/Unity/Launcher/appdrawermodel.cpp 2016-12-07 18:01:28 +0000
144@@ -0,0 +1,62 @@
145+/*
146+ * Copyright (C) 2016 Canonical, Ltd.
147+ *
148+ * This program is free software; you can redistribute it and/or modify
149+ * it under the terms of the GNU General Public License as published by
150+ * the Free Software Foundation; version 3.
151+ *
152+ * This program is distributed in the hope that it will be useful,
153+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
154+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
155+ * GNU General Public License for more details.
156+ *
157+ * You should have received a copy of the GNU General Public License
158+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
159+ */
160+
161+#include "appdrawermodel.h"
162+#include "ualwrapper.h"
163+
164+#include <QDebug>
165+#include <QDateTime>
166+
167+AppDrawerModel::AppDrawerModel(QObject *parent):
168+ AppDrawerModelInterface(parent)
169+{
170+ Q_FOREACH (const QString &appId, UalWrapper::installedApps()) {
171+ UalWrapper::AppInfo info = UalWrapper::getApplicationInfo(appId);
172+ if (!info.valid) {
173+ qWarning() << "Failed to get app info for app" << appId;
174+ continue;
175+ }
176+ m_list.append(new LauncherItem(appId, info.name, info.icon, this));
177+ m_list.last()->setKeywords(info.keywords);
178+ }
179+ qsrand(QDateTime::currentMSecsSinceEpoch() / 100);
180+}
181+
182+int AppDrawerModel::rowCount(const QModelIndex &parent) const
183+{
184+ Q_UNUSED(parent)
185+ return m_list.count();
186+}
187+
188+QVariant AppDrawerModel::data(const QModelIndex &index, int role) const
189+{
190+ switch (role) {
191+ case RoleAppId:
192+ return m_list.at(index.row())->appId();
193+ case RoleName:
194+ return m_list.at(index.row())->name();
195+ case RoleIcon:
196+ return m_list.at(index.row())->icon();
197+ case RoleKeywords:
198+ return m_list.at(index.row())->keywords();
199+ case RoleUsage:
200+ // FIXME: u-a-l needs to provide API for usage stats.
201+ // don't forget to drop the qsrand() call in the ctor when dropping this.
202+ return qrand();
203+ }
204+
205+ return QVariant();
206+}
207
208=== added file 'plugins/Unity/Launcher/appdrawermodel.h'
209--- plugins/Unity/Launcher/appdrawermodel.h 1970-01-01 00:00:00 +0000
210+++ plugins/Unity/Launcher/appdrawermodel.h 2016-12-07 18:01:28 +0000
211@@ -0,0 +1,33 @@
212+/*
213+ * Copyright (C) 2016 Canonical, Ltd.
214+ *
215+ * This program is free software; you can redistribute it and/or modify
216+ * it under the terms of the GNU General Public License as published by
217+ * the Free Software Foundation; version 3.
218+ *
219+ * This program is distributed in the hope that it will be useful,
220+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
221+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
222+ * GNU General Public License for more details.
223+ *
224+ * You should have received a copy of the GNU General Public License
225+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
226+ */
227+
228+
229+#include <unity/shell/launcher/AppDrawerModelInterface.h>
230+
231+#include "launcheritem.h"
232+
233+class AppDrawerModel: public AppDrawerModelInterface
234+{
235+ Q_OBJECT
236+public:
237+ AppDrawerModel(QObject* parent = nullptr);
238+
239+ int rowCount(const QModelIndex &parent) const override;
240+ QVariant data(const QModelIndex &index, int role) const override;
241+
242+private:
243+ QList<LauncherItem*> m_list;
244+};
245
246=== modified file 'plugins/Unity/Launcher/launcheritem.cpp'
247--- plugins/Unity/Launcher/launcheritem.cpp 2016-10-28 11:54:16 +0000
248+++ plugins/Unity/Launcher/launcheritem.cpp 2016-12-07 18:01:28 +0000
249@@ -90,6 +90,19 @@
250 }
251 }
252
253+QStringList LauncherItem::keywords() const
254+{
255+ return m_keywords;
256+}
257+
258+void LauncherItem::setKeywords(const QStringList &keywords)
259+{
260+ if (m_keywords != keywords) {
261+ m_keywords = keywords;
262+ Q_EMIT keywordsChanged(keywords);
263+ }
264+}
265+
266 bool LauncherItem::pinned() const
267 {
268 return m_pinned;
269
270=== modified file 'plugins/Unity/Launcher/launcheritem.h'
271--- plugins/Unity/Launcher/launcheritem.h 2016-05-10 15:51:00 +0000
272+++ plugins/Unity/Launcher/launcheritem.h 2016-12-07 18:01:28 +0000
273@@ -37,6 +37,7 @@
274 QString appId() const override;
275 QString name() const override;
276 QString icon() const override;
277+ QStringList keywords() const override;
278 bool pinned() const override;
279 bool running() const override;
280 bool recent() const override;
281@@ -52,6 +53,7 @@
282 private:
283 void setName(const QString &name);
284 void setIcon(const QString &icon);
285+ void setKeywords(const QStringList &keywords);
286 void setPinned(bool pinned);
287 void setRunning(bool running);
288 void setRecent(bool recent);
289@@ -66,6 +68,7 @@
290 QString m_appId;
291 QString m_name;
292 QString m_icon;
293+ QStringList m_keywords;
294 bool m_pinned;
295 bool m_running;
296 bool m_recent;
297@@ -79,6 +82,7 @@
298 QuickListEntry m_quitAction;
299
300 friend class LauncherModel;
301+ friend class AppDrawerModel;
302 };
303
304 #endif // LAUNCHERITEM_H
305
306=== modified file 'plugins/Unity/Launcher/launchermodel.cpp'
307--- plugins/Unity/Launcher/launchermodel.cpp 2016-09-23 15:10:26 +0000
308+++ plugins/Unity/Launcher/launchermodel.cpp 2016-12-07 18:01:28 +0000
309@@ -19,18 +19,14 @@
310 #include "gsettings.h"
311 #include "dbusinterface.h"
312 #include "asadapter.h"
313+#include "ualwrapper.h"
314
315-#include <ubuntu-app-launch/appid.h>
316-#include <ubuntu-app-launch/application.h>
317-#include <ubuntu-app-launch/registry.h>
318 #include <unity/shell/application/ApplicationInfoInterface.h>
319 #include <unity/shell/application/MirSurfaceListInterface.h>
320
321 #include <QDesktopServices>
322 #include <QDebug>
323
324-namespace ual = ubuntu::app_launch;
325-
326 using namespace unity::shell::application;
327
328 LauncherModel::LauncherModel(QObject *parent):
329@@ -38,8 +34,7 @@
330 m_settings(new GSettings(this)),
331 m_dbusIface(new DBusInterface(this)),
332 m_asAdapter(new ASAdapter()),
333- m_appManager(nullptr),
334- m_ualRegistry(std::make_shared<ual::Registry>())
335+ m_appManager(nullptr)
336 {
337 connect(m_dbusIface, &DBusInterface::countChanged, this, &LauncherModel::countChanged);
338 connect(m_dbusIface, &DBusInterface::countVisibleChanged, this, &LauncherModel::countVisibleChanged);
339@@ -159,7 +154,7 @@
340 index = m_list.count();
341 }
342
343- auto appInfo = getApplicationInfo(appId);
344+ UalWrapper::AppInfo appInfo = UalWrapper::getApplicationInfo(appId);
345 if (!appInfo.valid) {
346 qWarning() << "Can't pin application, appId not found:" << appId;
347 return;
348@@ -335,32 +330,6 @@
349 return -1;
350 }
351
352-LauncherModel::AppInfo LauncherModel::getApplicationInfo(const QString &appId)
353-{
354- AppInfo info;
355-
356- ual::AppID ualAppId = ual::AppID::find(m_ualRegistry, appId.toStdString());
357- if (ualAppId.empty()) {
358- return info;
359- }
360-
361- std::shared_ptr<ual::Application> ualApp;
362- try
363- {
364- ualApp = ual::Application::create(ualAppId, m_ualRegistry);
365- }
366- catch (std::runtime_error &e)
367- {
368- qWarning() << "Couldn't find application info for" << appId << "-" << e.what();
369- return info;
370- }
371-
372- info.valid = true;
373- info.name = QString::fromStdString(ualApp->info()->name());
374- info.icon = QString::fromStdString(ualApp->info()->iconPath());
375- return info;
376-}
377-
378 void LauncherModel::progressChanged(const QString &appId, int progress)
379 {
380 const int idx = findApplication(appId);
381@@ -408,7 +377,7 @@
382 }
383 } else {
384 // Need to create a new LauncherItem and show the highlight
385- auto appInfo = getApplicationInfo(appId);
386+ UalWrapper::AppInfo appInfo = UalWrapper::getApplicationInfo(appId);
387 if (countVisible && appInfo.valid) {
388 LauncherItem *item = new LauncherItem(appId,
389 appInfo.name,
390@@ -428,7 +397,7 @@
391 // First walk through all the existing items and see if we need to remove something
392 QList<LauncherItem*> toBeRemoved;
393 Q_FOREACH (LauncherItem* item, m_list) {
394- auto appInfo = getApplicationInfo(item->appId());
395+ UalWrapper::AppInfo appInfo = UalWrapper::getApplicationInfo(item->appId());
396 if (!appInfo.valid) {
397 // Application no longer available => drop it!
398 toBeRemoved << item;
399@@ -480,7 +449,7 @@
400 if (itemIndex == -1) {
401 // Need to add it. Just add it into the addedIndex to keep same ordering as the list
402 // in the settings.
403- auto appInfo = getApplicationInfo(entry);
404+ UalWrapper::AppInfo appInfo = UalWrapper::getApplicationInfo(entry);
405 if (!appInfo.valid) {
406 continue;
407 }
408
409=== modified file 'plugins/Unity/Launcher/launchermodel.h'
410--- plugins/Unity/Launcher/launchermodel.h 2016-09-23 14:44:26 +0000
411+++ plugins/Unity/Launcher/launchermodel.h 2016-12-07 18:01:28 +0000
412@@ -27,12 +27,6 @@
413 class DBusInterface;
414 class ASAdapter;
415
416-namespace ubuntu {
417- namespace app_launch {
418- class Registry;
419- }
420-}
421-
422 using namespace unity::shell::launcher;
423 using namespace unity::shell::application;
424
425@@ -73,13 +67,6 @@
426
427 void unpin(const QString &appId);
428
429- struct AppInfo {
430- bool valid = false;
431- QString name;
432- QString icon;
433- };
434- AppInfo getApplicationInfo(const QString &appId);
435-
436 private Q_SLOTS:
437 void countChanged(const QString &appId, int count);
438 void countVisibleChanged(const QString &appId, bool count);
439@@ -98,7 +85,6 @@
440 ASAdapter *m_asAdapter;
441
442 ApplicationManagerInterface *m_appManager;
443- std::shared_ptr<ubuntu::app_launch::Registry> m_ualRegistry;
444
445 friend class LauncherModelTest;
446 };
447
448=== modified file 'plugins/Unity/Launcher/plugin.cpp'
449--- plugins/Unity/Launcher/plugin.cpp 2015-09-14 09:11:08 +0000
450+++ plugins/Unity/Launcher/plugin.cpp 2016-12-07 18:01:28 +0000
451@@ -26,7 +26,7 @@
452 // local
453 #include "launchermodel.h"
454 #include "launcheritem.h"
455-
456+#include "appdrawermodel.h"
457
458 using namespace unity::shell::launcher;
459
460@@ -46,4 +46,5 @@
461 qmlRegisterSingletonType<LauncherModel>(uri, 0, 1, "LauncherModel", modelProvider);
462 qmlRegisterUncreatableType<LauncherItem>(uri, 0, 1, "LauncherItem", QStringLiteral("Can't create new Launcher Items in QML. Get them from the LauncherModel."));
463 qmlRegisterUncreatableType<QuickListModel>(uri, 0, 1, "QuickListModel", QStringLiteral("Can't create a QuickListModel in QML. Get them from the LauncherItems."));
464+ qmlRegisterType<AppDrawerModel>(uri, 0, 1, "AppDrawerModel");
465 }
466
467=== added file 'plugins/Unity/Launcher/ualwrapper.cpp'
468--- plugins/Unity/Launcher/ualwrapper.cpp 1970-01-01 00:00:00 +0000
469+++ plugins/Unity/Launcher/ualwrapper.cpp 2016-12-07 18:01:28 +0000
470@@ -0,0 +1,73 @@
471+/*
472+ * Copyright (C) 2016 Canonical, Ltd.
473+ *
474+ * This program is free software; you can redistribute it and/or modify
475+ * it under the terms of the GNU General Public License as published by
476+ * the Free Software Foundation; version 3.
477+ *
478+ * This program is distributed in the hope that it will be useful,
479+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
480+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
481+ * GNU General Public License for more details.
482+ *
483+ * You should have received a copy of the GNU General Public License
484+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
485+ */
486+
487+#include <QDebug>
488+
489+#include "ualwrapper.h"
490+
491+#include <ubuntu-app-launch/registry.h>
492+using namespace ubuntu::app_launch;
493+
494+UalWrapper::UalWrapper(QObject *parent):
495+ QObject(parent)
496+{
497+
498+}
499+
500+QStringList UalWrapper::installedApps()
501+{
502+ QStringList appIds;
503+ try {
504+ for (const std::shared_ptr<Application> &app : Registry::installedApps()) {
505+ if (!app->appId().package.value().empty()) {
506+ appIds << QString::fromStdString(app->appId().package.value() + "_" + app->appId().appname.value());
507+ } else {
508+ appIds << QString::fromStdString(app->appId().appname);
509+ }
510+ }
511+ } catch (const std::runtime_error &e) {
512+ qWarning() << "ubuntu-all-launch threw an exception listing apps:" << e.what();
513+ }
514+
515+ return appIds;
516+}
517+
518+UalWrapper::AppInfo UalWrapper::getApplicationInfo(const QString &appId)
519+{
520+ AppInfo info;
521+
522+ try {
523+ AppID ualAppId = AppID::find(appId.toStdString());
524+ if (ualAppId.empty()) {
525+ qWarning() << "Empty ualAppId result for" << appId;
526+ return info;
527+ }
528+
529+ std::shared_ptr<Application> ualApp;
530+ ualApp = Application::create(ualAppId, Registry::getDefault());
531+
532+ info.name = QString::fromStdString(ualApp->info()->name());
533+ info.icon = QString::fromStdString(ualApp->info()->iconPath());
534+ for (const std::string &keyword : ualApp->info()->keywords().value()) {
535+ info.keywords << QString::fromStdString(keyword);
536+ }
537+ info.valid = true;
538+ } catch (const std::runtime_error &e) {
539+ qWarning() << "ubuntu-app-launch threw an exception getting app info for appId:" << appId << ":" << e.what();
540+ }
541+
542+ return info;
543+}
544
545=== added file 'plugins/Unity/Launcher/ualwrapper.h'
546--- plugins/Unity/Launcher/ualwrapper.h 1970-01-01 00:00:00 +0000
547+++ plugins/Unity/Launcher/ualwrapper.h 2016-12-07 18:01:28 +0000
548@@ -0,0 +1,35 @@
549+/*
550+ * Copyright (C) 2016 Canonical, Ltd.
551+ *
552+ * This program is free software; you can redistribute it and/or modify
553+ * it under the terms of the GNU General Public License as published by
554+ * the Free Software Foundation; version 3.
555+ *
556+ * This program is distributed in the hope that it will be useful,
557+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
558+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
559+ * GNU General Public License for more details.
560+ *
561+ * You should have received a copy of the GNU General Public License
562+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
563+ */
564+
565+#include <QObject>
566+
567+class UalWrapper: public QObject
568+{
569+ Q_OBJECT
570+public:
571+ struct AppInfo {
572+ bool valid = false;
573+ QString name;
574+ QString icon;
575+ QStringList keywords;
576+ };
577+
578+ UalWrapper(QObject* parent = nullptr);
579+
580+ static QStringList installedApps();
581+ static AppInfo getApplicationInfo(const QString &appId);
582+
583+};
584
585=== modified file 'plugins/Utils/CMakeLists.txt'
586--- plugins/Utils/CMakeLists.txt 2016-06-29 18:05:44 +0000
587+++ plugins/Utils/CMakeLists.txt 2016-12-07 18:01:28 +0000
588@@ -15,6 +15,10 @@
589 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationManagerInterface.h
590 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationInfoInterface.h
591 applicationsfiltermodel.cpp
592+ ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/AppDrawerModelInterface.h
593+ ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherItemInterface.h
594+ ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherModelInterface.h
595+ appdrawerproxymodel.cpp
596 constants.cpp
597 WindowInputMonitor.cpp
598 inputwatcher.cpp
599
600=== added file 'plugins/Utils/appdrawerproxymodel.cpp'
601--- plugins/Utils/appdrawerproxymodel.cpp 1970-01-01 00:00:00 +0000
602+++ plugins/Utils/appdrawerproxymodel.cpp 2016-12-07 18:01:28 +0000
603@@ -0,0 +1,189 @@
604+/*
605+ * Copyright (C) 2016 Canonical, Ltd.
606+ *
607+ * This program is free software; you can redistribute it and/or modify
608+ * it under the terms of the GNU General Public License as published by
609+ * the Free Software Foundation; version 3.
610+ *
611+ * This program is distributed in the hope that it will be useful,
612+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
613+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
614+ * GNU General Public License for more details.
615+ *
616+ * You should have received a copy of the GNU General Public License
617+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
618+ */
619+
620+#include "appdrawerproxymodel.h"
621+
622+#include <unity/shell/launcher/LauncherItemInterface.h>
623+
624+#include <QDebug>
625+
626+AppDrawerProxyModel::AppDrawerProxyModel(QObject *parent):
627+ QSortFilterProxyModel(parent)
628+{
629+ setSortRole(AppDrawerModelInterface::RoleName);
630+ setSortLocaleAware(true);
631+ sort(0);
632+
633+ connect(this, &QAbstractListModel::rowsInserted, this, &AppDrawerProxyModel::countChanged);
634+ connect(this, &QAbstractListModel::rowsRemoved, this, &AppDrawerProxyModel::countChanged);
635+ connect(this, &QAbstractListModel::layoutChanged, this, &AppDrawerProxyModel::countChanged);
636+}
637+
638+QAbstractItemModel *AppDrawerProxyModel::source() const
639+{
640+ return m_source;
641+}
642+
643+void AppDrawerProxyModel::setSource(QAbstractItemModel *source)
644+{
645+ if (m_source != source) {
646+ m_source = source;
647+ setSourceModel(m_source);
648+ setSortRole(m_sortBy == SortByAToZ ? AppDrawerModelInterface::RoleName : AppDrawerModelInterface::RoleUsage);
649+ connect(m_source, &QAbstractItemModel::rowsRemoved, this, &AppDrawerProxyModel::invalidateFilter);
650+ connect(m_source, &QAbstractItemModel::rowsInserted, this, &AppDrawerProxyModel::invalidateFilter);
651+ Q_EMIT sourceChanged();
652+ }
653+}
654+
655+AppDrawerProxyModel::GroupBy AppDrawerProxyModel::group() const
656+{
657+ return m_group;
658+}
659+
660+void AppDrawerProxyModel::setGroup(AppDrawerProxyModel::GroupBy group)
661+{
662+ if (m_group != group) {
663+ m_group = group;
664+ Q_EMIT groupChanged();
665+ invalidateFilter();
666+ }
667+}
668+
669+QString AppDrawerProxyModel::filterLetter() const
670+{
671+ return m_filterLetter;
672+}
673+
674+void AppDrawerProxyModel::setFilterLetter(const QString &filterLetter)
675+{
676+ if (m_filterLetter != filterLetter) {
677+ m_filterLetter = filterLetter;
678+ Q_EMIT filterLetterChanged();
679+ invalidateFilter();
680+ }
681+}
682+
683+QString AppDrawerProxyModel::filterString() const
684+{
685+ return m_filterString;
686+}
687+
688+void AppDrawerProxyModel::setFilterString(const QString &filterString)
689+{
690+ if (m_filterString != filterString) {
691+ m_filterString = filterString;
692+ Q_EMIT filterStringChanged();
693+ invalidateFilter();
694+ }
695+}
696+
697+AppDrawerProxyModel::SortBy AppDrawerProxyModel::sortBy() const
698+{
699+ return m_sortBy;
700+}
701+
702+void AppDrawerProxyModel::setSortBy(AppDrawerProxyModel::SortBy sortBy)
703+{
704+ if (m_sortBy != sortBy) {
705+ m_sortBy = sortBy;
706+ Q_EMIT sortByChanged();
707+ setSortRole(m_sortBy == SortByAToZ ? AppDrawerModelInterface::RoleName : AppDrawerModelInterface::RoleUsage);
708+ sort(0);
709+ }
710+}
711+
712+int AppDrawerProxyModel::count() const
713+{
714+ return rowCount();
715+}
716+
717+QVariant AppDrawerProxyModel::data(const QModelIndex &index, int role) const
718+{
719+ QModelIndex idx = mapToSource(index);
720+ if (role == Qt::UserRole) {
721+ QString name = m_source->data(idx, AppDrawerModelInterface::RoleName).toString();
722+ return name.length() > 0 ? QString(name.at(0)).toUpper() : QChar();
723+ }
724+ return m_source->data(idx, role);
725+}
726+
727+QHash<int, QByteArray> AppDrawerProxyModel::roleNames() const
728+{
729+ if (m_source) {
730+ QHash<int, QByteArray> roles = m_source->roleNames();
731+ roles.insert(Qt::UserRole, "letter");
732+ return roles;
733+ }
734+ return QHash<int, QByteArray>();
735+}
736+
737+bool AppDrawerProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
738+{
739+ Q_UNUSED(source_parent)
740+
741+ if (m_group == GroupByAToZ && source_row > 0) {
742+ QString currentName = m_source->data(m_source->index(source_row, 0), AppDrawerModelInterface::RoleName).toString();
743+ QChar currentLetter = currentName.length() > 0 ? currentName.at(0) : QChar();
744+ QString previousName = m_source->data(m_source->index(source_row - 1,0 ), AppDrawerModelInterface::RoleName).toString();
745+ QChar previousLetter = previousName.length() > 0 ? previousName.at(0) : QChar();
746+ if (currentLetter.toLower() == previousLetter.toLower()) {
747+ return false;
748+ }
749+ } else if(m_group == GroupByAll && source_row > 0) {
750+ return false;
751+ }
752+ if (!m_filterLetter.isEmpty()) {
753+ QString currentName = m_source->data(m_source->index(source_row, 0), AppDrawerModelInterface::RoleName).toString();
754+ QString currentLetter = currentName.length() > 0 ? QString(currentName.at(0)) : QString();
755+ if (currentLetter.toLower() != m_filterLetter.toLower()) {
756+ return false;
757+ }
758+ }
759+ if (!m_filterString.isEmpty()) {
760+ QStringList allWords = m_source->data(m_source->index(source_row, 0), AppDrawerModelInterface::RoleKeywords).toStringList();
761+ allWords.prepend(m_source->data(m_source->index(source_row, 0), AppDrawerModelInterface::RoleName).toString());
762+ bool found = false;
763+ Q_FOREACH (const QString currentWord, allWords) {
764+ if (currentWord.toLower().startsWith(m_filterString.toLower())) {
765+ found = true;
766+ break;
767+ }
768+ }
769+ if (!found) {
770+ return false;
771+ }
772+ }
773+ return true;
774+}
775+
776+QString AppDrawerProxyModel::appId(int index) const
777+{
778+ if (index >= 0 && index < rowCount()) {
779+ QModelIndex sourceIndex = mapToSource(this->index(index, 0));
780+
781+ AppDrawerModelInterface* adm = dynamic_cast<AppDrawerModelInterface*>(m_source);
782+ if (adm) {
783+ return adm->data(sourceIndex, AppDrawerModelInterface::RoleAppId).toString();
784+ }
785+
786+ AppDrawerProxyModel* adpm = qobject_cast<AppDrawerProxyModel*>(m_source);
787+ if (adpm) {
788+ return adpm->appId(sourceIndex.row());
789+ }
790+ }
791+ return nullptr;
792+}
793
794=== added file 'plugins/Utils/appdrawerproxymodel.h'
795--- plugins/Utils/appdrawerproxymodel.h 1970-01-01 00:00:00 +0000
796+++ plugins/Utils/appdrawerproxymodel.h 2016-12-07 18:01:28 +0000
797@@ -0,0 +1,87 @@
798+/*
799+ * Copyright (C) 2016 Canonical, Ltd.
800+ *
801+ * This program is free software; you can redistribute it and/or modify
802+ * it under the terms of the GNU General Public License as published by
803+ * the Free Software Foundation; version 3.
804+ *
805+ * This program is distributed in the hope that it will be useful,
806+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
807+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
808+ * GNU General Public License for more details.
809+ *
810+ * You should have received a copy of the GNU General Public License
811+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
812+ */
813+
814+#include <QSortFilterProxyModel>
815+
816+#include <unity/shell/launcher/AppDrawerModelInterface.h>
817+
818+using namespace unity::shell::launcher;
819+
820+class AppDrawerProxyModel: public QSortFilterProxyModel
821+{
822+ Q_OBJECT
823+ Q_ENUMS(GroupBy)
824+ Q_ENUMS(SortBy)
825+ Q_PROPERTY(QAbstractItemModel* source READ source WRITE setSource NOTIFY sourceChanged)
826+ Q_PROPERTY(GroupBy group READ group WRITE setGroup NOTIFY groupChanged)
827+ Q_PROPERTY(QString filterLetter READ filterLetter WRITE setFilterLetter NOTIFY filterLetterChanged)
828+ Q_PROPERTY(QString filterString READ filterString WRITE setFilterString NOTIFY filterStringChanged)
829+ Q_PROPERTY(SortBy sortBy READ sortBy WRITE setSortBy NOTIFY sortByChanged)
830+ Q_PROPERTY(int count READ count NOTIFY countChanged)
831+
832+public:
833+ enum GroupBy {
834+ GroupByNone,
835+ GroupByAll,
836+ GroupByAToZ
837+ };
838+ enum SortBy {
839+ SortByAToZ,
840+ SortByUsage
841+ };
842+
843+ AppDrawerProxyModel(QObject* parent = nullptr);
844+
845+ QAbstractItemModel* source() const;
846+ void setSource(QAbstractItemModel* source);
847+
848+ GroupBy group() const;
849+ void setGroup(GroupBy group);
850+
851+ QString filterLetter() const;
852+ void setFilterLetter(const QString &filterLetter);
853+
854+ QString filterString() const;
855+ void setFilterString(const QString &filterString);
856+
857+ SortBy sortBy() const;
858+ void setSortBy(SortBy sortBy);
859+
860+ int count() const;
861+
862+ QVariant data(const QModelIndex &index, int role) const override;
863+ QHash<int, QByteArray> roleNames() const override;
864+
865+ Q_INVOKABLE QString appId(int index) const;
866+
867+protected:
868+ bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override;
869+
870+Q_SIGNALS:
871+ void sourceChanged();
872+ void groupChanged();
873+ void filterLetterChanged();
874+ void filterStringChanged();
875+ void sortByChanged();
876+ void countChanged();
877+
878+private:
879+ QAbstractItemModel* m_source = nullptr;
880+ GroupBy m_group = GroupByNone;
881+ QString m_filterLetter;
882+ QString m_filterString;
883+ SortBy m_sortBy = SortByAToZ;
884+};
885
886=== modified file 'plugins/Utils/plugin.cpp'
887--- plugins/Utils/plugin.cpp 2016-06-28 20:38:00 +0000
888+++ plugins/Utils/plugin.cpp 2016-12-07 18:01:28 +0000
889@@ -39,6 +39,7 @@
890 #include "deviceconfigparser.h"
891 #include "globalfunctions.h"
892 #include "URLDispatcher.h"
893+#include "appdrawerproxymodel.h"
894
895 static QObject *createWindowStateStorage(QQmlEngine *engine, QJSEngine *scriptEngine)
896 {
897@@ -82,4 +83,5 @@
898 qmlRegisterType<DeviceConfigParser>(uri, 0, 1, "DeviceConfigParser");
899 qmlRegisterSingletonType<GlobalFunctions>(uri, 0, 1, "Functions", createGlobalFunctions);
900 qmlRegisterType<URLDispatcher>(uri, 0, 1, "URLDispatcher");
901+ qmlRegisterType<AppDrawerProxyModel>(uri, 0, 1, "AppDrawerProxyModel");
902 }
903
904=== modified file 'qml/Components/KeyboardShortcutsOverlay.qml'
905--- qml/Components/KeyboardShortcutsOverlay.qml 2016-05-11 11:09:42 +0000
906+++ qml/Components/KeyboardShortcutsOverlay.qml 2016-12-07 18:01:28 +0000
907@@ -173,6 +173,19 @@
908 Layout.maximumWidth: maxTextSize
909 }
910
911+ Label {
912+ text: i18n.tr("Super + A")
913+ fontSize: "small"
914+ font.weight: Font.Medium
915+ }
916+ Label {
917+ text: i18n.tr("Opens the Application Drawer.")
918+ fontSize: "small"
919+ font.weight: Font.Light
920+ wrapMode: Text.Wrap
921+ Layout.maximumWidth: maxTextSize
922+ }
923+
924
925 // Scopes section
926 Item { Layout.columnSpan: 2; height: units.gu(2) }
927
928=== added file 'qml/Launcher/BackgroundBlur.qml'
929--- qml/Launcher/BackgroundBlur.qml 1970-01-01 00:00:00 +0000
930+++ qml/Launcher/BackgroundBlur.qml 2016-12-07 18:01:28 +0000
931@@ -0,0 +1,81 @@
932+/*
933+ * Copyright (C) 2016 Canonical, Ltd.
934+ *
935+ * This program is free software; you can redistribute it and/or modify
936+ * it under the terms of the GNU General Public License as published by
937+ * the Free Software Foundation; version 3.
938+ *
939+ * This program is distributed in the hope that it will be useful,
940+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
941+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
942+ * GNU General Public License for more details.
943+ *
944+ * You should have received a copy of the GNU General Public License
945+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
946+ */
947+
948+import QtQuick 2.4
949+import Ubuntu.Components 1.3
950+import QtGraphicalEffects 1.0
951+
952+Item {
953+ id: root
954+
955+ property int blurAmount: 32
956+ property Item sourceItem
957+ property rect blurRect: Qt.rect(0,0,0,0)
958+ property alias cached: fastBlur.cached
959+
960+ Rectangle {
961+ id: blurMask
962+ color: "yellow"
963+ x: blurRect.x
964+ y: blurRect.y
965+ width: blurRect.width
966+ height: blurRect.height
967+ }
968+
969+ ShaderEffect {
970+ id: maskedBlurEffect
971+ x: blurRect.x
972+ y: blurRect.y
973+ width: blurRect.width
974+ height: blurRect.height
975+
976+ property variant source: ShaderEffectSource {
977+ id: shaderEffectSource
978+ sourceItem: root.sourceItem
979+ hideSource: false
980+ sourceRect: root.blurRect
981+ }
982+
983+ property var mask: ShaderEffectSource {
984+ sourceItem: blurMask
985+ hideSource: true
986+ }
987+
988+ fragmentShader: "
989+ varying highp vec2 qt_TexCoord0;
990+ uniform sampler2D source;
991+ uniform sampler2D mask;
992+ void main(void)
993+ {
994+ highp vec4 sourceColor = texture2D(source, qt_TexCoord0);
995+ highp vec4 maskColor = texture2D(mask, qt_TexCoord0);
996+
997+ sourceColor *= maskColor.a;
998+
999+ gl_FragColor = sourceColor;
1000+ }"
1001+ }
1002+
1003+ FastBlur {
1004+ id: fastBlur
1005+ x: blurRect.x
1006+ y: blurRect.y
1007+ width: blurRect.width
1008+ height: blurRect.height
1009+ source: maskedBlurEffect
1010+ radius: Math.min(blurAmount, 128)
1011+ }
1012+ }
1013
1014=== added file 'qml/Launcher/Drawer.qml'
1015--- qml/Launcher/Drawer.qml 1970-01-01 00:00:00 +0000
1016+++ qml/Launcher/Drawer.qml 2016-12-07 18:01:28 +0000
1017@@ -0,0 +1,306 @@
1018+/*
1019+ * Copyright (C) 2016 Canonical, Ltd.
1020+ *
1021+ * This program is free software; you can redistribute it and/or modify
1022+ * it under the terms of the GNU General Public License as published by
1023+ * the Free Software Foundation; version 3.
1024+ *
1025+ * This program is distributed in the hope that it will be useful,
1026+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1027+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1028+ * GNU General Public License for more details.
1029+ *
1030+ * You should have received a copy of the GNU General Public License
1031+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1032+ */
1033+
1034+import QtQuick 2.4
1035+import Ubuntu.Components 1.3
1036+import Unity.Launcher 0.1
1037+import Utils 0.1
1038+import "../Components"
1039+import Qt.labs.settings 1.0
1040+
1041+FocusScope {
1042+ id: root
1043+
1044+ property int panelWidth: 0
1045+ readonly property bool moving: listLoader.item && listLoader.item.moving
1046+
1047+ signal applicationSelected(string appId)
1048+
1049+ property bool draggingHorizontally: false
1050+ property int dragDistance: 0
1051+
1052+ onFocusChanged: {
1053+ if (focus) {
1054+ searchField.selectAll();
1055+ }
1056+ }
1057+
1058+ function focusInput() {
1059+ searchField.selectAll();
1060+ searchField.focus = true;
1061+ }
1062+
1063+ Settings {
1064+ property alias selectedTab: sections.selectedIndex
1065+ }
1066+
1067+ MouseArea {
1068+ anchors.fill: parent
1069+ hoverEnabled: true
1070+ acceptedButtons: Qt.AllButtons
1071+ onWheel: wheel.accepted = true
1072+ }
1073+
1074+ Rectangle {
1075+ anchors.fill: parent
1076+ color: "#BF000000"
1077+
1078+ AppDrawerModel {
1079+ id: appDrawerModel
1080+ }
1081+
1082+ AppDrawerProxyModel {
1083+ id: sortProxyModel
1084+ source: appDrawerModel
1085+ filterString: searchField.displayText
1086+ sortBy: AppDrawerProxyModel.SortByAToZ
1087+ }
1088+
1089+ Item {
1090+ id: contentContainer
1091+ anchors.fill: parent
1092+ anchors.leftMargin: root.panelWidth
1093+
1094+ TextField {
1095+ id: searchField
1096+ anchors { left: parent.left; top: parent.top; right: parent.right; margins: units.gu(1) }
1097+ placeholderText: i18n.tr("Search…")
1098+ focus: true
1099+ onAccepted: {
1100+ if (searchField.displayText != "" && listLoader.item && listLoader.item.currentItem) {
1101+ root.applicationSelected(listLoader.item.getFirstAppId());
1102+ }
1103+ }
1104+ }
1105+
1106+ Item {
1107+ id: sectionsContainer
1108+ anchors { left: parent.left; top: searchField.bottom; right: parent.right; }
1109+ height: sections.height
1110+ clip: true
1111+ z: 2
1112+
1113+ Sections {
1114+ id: sections
1115+ width: parent.width
1116+ actions: [
1117+ Action {
1118+ text: i18n.ctr("Apps sorted alphabetically", "A-Z")
1119+ // TODO: Disabling this for now as we don't get the right input from u-a-l yet.
1120+// },
1121+// Action {
1122+// text: i18n.ctr("Most used apps", "Most used")
1123+ }
1124+ ]
1125+
1126+ Rectangle {
1127+ anchors.bottom: parent.bottom
1128+ height: units.dp(1)
1129+ color: 'gray'
1130+ width: contentContainer.width
1131+ }
1132+ }
1133+ }
1134+
1135+ Loader {
1136+ id: listLoader
1137+ anchors { left: parent.left; top: sectionsContainer.bottom; right: parent.right; bottom: parent.bottom; leftMargin: units.gu(1); rightMargin: units.gu(1) }
1138+ sourceComponent: {
1139+ switch (sections.selectedIndex) {
1140+ case 0: return aToZComponent;
1141+ case 1: return mostUsedComponent;
1142+ }
1143+ }
1144+ Binding {
1145+ target: listLoader.item || null
1146+ property: "objectName"
1147+ value: "drawerItemList"
1148+ }
1149+ }
1150+
1151+ MouseArea {
1152+ parent: listLoader.item ? listLoader.item : null
1153+ anchors.fill: parent
1154+ propagateComposedEvents: true
1155+ property int oldX: 0
1156+ onPressed: {
1157+ oldX = mouseX;
1158+ }
1159+ onMouseXChanged: {
1160+ var diff = oldX - mouseX;
1161+ root.draggingHorizontally |= diff > units.gu(2);
1162+ if (!root.draggingHorizontally) {
1163+ return;
1164+ }
1165+ propagateComposedEvents = false;
1166+ parent.interactive = false;
1167+ root.dragDistance += diff;
1168+ oldX = mouseX
1169+ }
1170+ onReleased: {
1171+ if (root.draggingHorizontally) {
1172+ root.draggingHorizontally = false;
1173+ parent.interactive = true;
1174+ }
1175+ reactivateTimer.start();
1176+ }
1177+ Timer {
1178+ id: reactivateTimer
1179+ interval: 0
1180+ onTriggered: parent.propagateComposedEvents = true;
1181+ }
1182+ }
1183+
1184+ Component {
1185+ id: mostUsedComponent
1186+ DrawerListView {
1187+
1188+ header: MoreAppsHeader {
1189+ width: parent.width
1190+ height: units.gu(6)
1191+ }
1192+
1193+ model: AppDrawerProxyModel {
1194+ source: sortProxyModel
1195+ group: AppDrawerProxyModel.GroupByAll
1196+ sortBy: AppDrawerProxyModel.SortByUsage
1197+ }
1198+
1199+ delegate: UbuntuShape {
1200+ width: parent.width
1201+ color: "#20ffffff"
1202+ aspect: UbuntuShape.Flat
1203+ // NOTE: Cannot use gridView.rows here as it would evaluate to 0 at first and only update later,
1204+ // which messes up the ListView.
1205+ height: (Math.ceil(mostUsedGridView.model.count / mostUsedGridView.columns) * mostUsedGridView.delegateHeight) + units.gu(2)
1206+
1207+ readonly property string appId: model.appId
1208+
1209+ DrawerGridView {
1210+ id: mostUsedGridView
1211+ anchors.fill: parent
1212+ topMargin: units.gu(1)
1213+ bottomMargin: units.gu(1)
1214+ clip: true
1215+
1216+ model: sortProxyModel
1217+
1218+ delegateWidth: units.gu(8)
1219+ delegateHeight: units.gu(10)
1220+ delegate: drawerDelegateComponent
1221+ }
1222+ }
1223+ }
1224+ }
1225+
1226+ Component {
1227+ id: aToZComponent
1228+ DrawerListView {
1229+
1230+ header: MoreAppsHeader {
1231+ width: parent.width
1232+ height: units.gu(6)
1233+ }
1234+
1235+ model: AppDrawerProxyModel {
1236+ source: sortProxyModel
1237+ sortBy: AppDrawerProxyModel.SortByAToZ
1238+ group: AppDrawerProxyModel.GroupByAToZ
1239+ }
1240+
1241+ delegate: UbuntuShape {
1242+ width: parent.width
1243+ color: "#20ffffff"
1244+ aspect: UbuntuShape.Flat
1245+
1246+ readonly property string appId: model.appId
1247+
1248+ // NOTE: Cannot use gridView.rows here as it would evaluate to 0 at first and only update later,
1249+ // which messes up the ListView.
1250+ height: (Math.ceil(gridView.model.count / gridView.columns) * gridView.delegateHeight) +
1251+ categoryNameLabel.implicitHeight + units.gu(2)
1252+
1253+ Label {
1254+ id: categoryNameLabel
1255+ anchors { left: parent.left; top: parent.top; right: parent.right; margins: units.gu(1) }
1256+ text: model.letter
1257+ }
1258+
1259+ DrawerGridView {
1260+ id: gridView
1261+ anchors { left: parent.left; top: categoryNameLabel.bottom; right: parent.right; topMargin: units.gu(1) }
1262+ height: rows * delegateHeight
1263+
1264+ interactive: false
1265+
1266+ model: AppDrawerProxyModel {
1267+ id: categoryModel
1268+ source: sortProxyModel
1269+ filterLetter: model.letter
1270+ }
1271+ delegateWidth: units.gu(8)
1272+ delegateHeight: units.gu(10)
1273+ delegate: drawerDelegateComponent
1274+ }
1275+ }
1276+ }
1277+ }
1278+ }
1279+
1280+ Component {
1281+ id: drawerDelegateComponent
1282+ AbstractButton {
1283+ width: GridView.view.cellWidth
1284+ height: units.gu(10)
1285+ objectName: "drawerItem_" + model.appId
1286+
1287+ onClicked: root.applicationSelected(model.appId)
1288+
1289+ Column {
1290+ width: units.gu(8)
1291+ anchors.horizontalCenter: parent.horizontalCenter
1292+ height: childrenRect.height
1293+ spacing: units.gu(1)
1294+
1295+ UbuntuShape {
1296+ id: appIcon
1297+ width: units.gu(6)
1298+ height: 7.5 / 8 * width
1299+ anchors.horizontalCenter: parent.horizontalCenter
1300+ backgroundMode: UbuntuShape.SolidColor
1301+ backgroundColor: UbuntuColors.lightGrey
1302+ radius: "medium"
1303+ borderSource: 'undefined'
1304+ source: Image {
1305+ id: sourceImage
1306+ sourceSize.width: appIcon.width
1307+ source: model.icon
1308+ }
1309+ sourceFillMode: UbuntuShape.PreserveAspectCrop
1310+ }
1311+
1312+ Label {
1313+ text: model.name
1314+ width: parent.width
1315+ horizontalAlignment: Text.AlignHCenter
1316+ fontSize: "small"
1317+ elide: Text.ElideRight
1318+ }
1319+ }
1320+ }
1321+ }
1322+ }
1323+}
1324
1325=== added file 'qml/Launcher/DrawerGridView.qml'
1326--- qml/Launcher/DrawerGridView.qml 1970-01-01 00:00:00 +0000
1327+++ qml/Launcher/DrawerGridView.qml 2016-12-07 18:01:28 +0000
1328@@ -0,0 +1,47 @@
1329+/*
1330+ * Copyright (C) 2016 Canonical, Ltd.
1331+ *
1332+ * This program is free software; you can redistribute it and/or modify
1333+ * it under the terms of the GNU General Public License as published by
1334+ * the Free Software Foundation; version 3.
1335+ *
1336+ * This program is distributed in the hope that it will be useful,
1337+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1338+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1339+ * GNU General Public License for more details.
1340+ *
1341+ * You should have received a copy of the GNU General Public License
1342+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1343+ */
1344+
1345+import QtQuick 2.4
1346+import "../Components"
1347+
1348+Item {
1349+ id: root
1350+
1351+ property int delegateWidth: units.gu(10)
1352+ property int delegateHeight: units.gu(10)
1353+ property alias delegate: gridView.delegate
1354+ property alias model: gridView.model
1355+ property alias interactive: gridView.interactive
1356+
1357+ property alias header: gridView.header
1358+ property alias topMargin: gridView.topMargin
1359+ property alias bottomMargin: gridView.bottomMargin
1360+
1361+ readonly property int columns: width / delegateWidth
1362+ readonly property int rows: Math.ceil(gridView.model.count / root.columns)
1363+
1364+ GridView {
1365+ id: gridView
1366+ anchors.fill: parent
1367+ leftMargin: spacing
1368+
1369+ readonly property int overflow: width - (root.columns * root.delegateWidth)
1370+ readonly property real spacing: overflow / (root.columns)
1371+
1372+ cellWidth: root.delegateWidth + spacing
1373+ cellHeight: root.delegateHeight
1374+ }
1375+}
1376
1377=== added file 'qml/Launcher/DrawerListView.qml'
1378--- qml/Launcher/DrawerListView.qml 1970-01-01 00:00:00 +0000
1379+++ qml/Launcher/DrawerListView.qml 2016-12-07 18:01:28 +0000
1380@@ -0,0 +1,32 @@
1381+/*
1382+ * Copyright (C) 2016 Canonical, Ltd.
1383+ *
1384+ * This program is free software; you can redistribute it and/or modify
1385+ * it under the terms of the GNU General Public License as published by
1386+ * the Free Software Foundation; version 3.
1387+ *
1388+ * This program is distributed in the hope that it will be useful,
1389+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1390+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1391+ * GNU General Public License for more details.
1392+ *
1393+ * You should have received a copy of the GNU General Public License
1394+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1395+ */
1396+
1397+import QtQuick 2.4
1398+import Ubuntu.Components 1.3
1399+import "../Components"
1400+
1401+ListView {
1402+ id: root
1403+ anchors.fill: parent
1404+ topMargin: units.gu(1)
1405+ bottomMargin: units.gu(1)
1406+ spacing: units.gu(1)
1407+ clip: true
1408+
1409+ function getFirstAppId() {
1410+ return model.appId(0);
1411+ }
1412+}
1413
1414=== modified file 'qml/Launcher/Launcher.qml'
1415--- qml/Launcher/Launcher.qml 2016-09-22 10:14:18 +0000
1416+++ qml/Launcher/Launcher.qml 2016-12-07 18:01:28 +0000
1417@@ -27,10 +27,12 @@
1418 property bool lockedVisible: false
1419 property bool available: true // can be used to disable all interactions
1420 property alias inverted: panel.inverted
1421+ property Item blurSource: null
1422+ property int topPanelHeight: 0
1423+ property bool drawerEnabled: true
1424
1425 property int panelWidth: units.gu(10)
1426 property int dragAreaWidth: units.gu(1)
1427- property int minimizeDistance: units.gu(26)
1428 property real progress: dragArea.dragging && dragArea.touchPosition.x > panelWidth ?
1429 (width * (dragArea.touchPosition.x-panelWidth) / (width - panelWidth)) : 0
1430
1431@@ -43,13 +45,11 @@
1432 readonly property alias shortcutHintsShown: panel.shortcutHintsShown
1433
1434 readonly property bool shown: panel.x > -panel.width
1435+ readonly property bool drawerShown: drawer.x == 0
1436
1437 // emitted when an application is selected
1438 signal launcherApplicationSelected(string appId)
1439
1440- // emitted when the apps dash should be shown because of a swipe gesture
1441- signal dash()
1442-
1443 // emitted when the dash icon in the launcher has been tapped
1444 signal showDashHome()
1445
1446@@ -62,6 +62,9 @@
1447 }
1448
1449 onSuperPressedChanged: {
1450+ if (state == "drawer")
1451+ return;
1452+
1453 if (superPressed) {
1454 superPressTimer.start();
1455 superLongPressTimer.start();
1456@@ -132,7 +135,7 @@
1457 }
1458
1459 function pushEdge(amount) {
1460- if (root.state === "") {
1461+ if (root.state === "" || root.state == "visible" || root.state == "visibleTemporary") {
1462 edgeBarrier.push(amount);
1463 }
1464 }
1465@@ -143,6 +146,22 @@
1466 switchToNextState("visible")
1467 }
1468
1469+ function openDrawer(focusInputField) {
1470+ if (!drawerEnabled) {
1471+ return;
1472+ }
1473+
1474+ panel.shortcutHintsShown = false;
1475+ superPressTimer.stop();
1476+ superLongPressTimer.stop();
1477+ root.focus = true;
1478+ drawer.focus = true;
1479+ if (focusInputField) {
1480+ drawer.focusInput();
1481+ }
1482+ switchToNextState("drawer")
1483+ }
1484+
1485 Keys.onPressed: {
1486 switch (event.key) {
1487 case Qt.Key_Backtab:
1488@@ -278,7 +297,7 @@
1489 InverseMouseArea {
1490 id: closeMouseArea
1491 anchors.fill: panel
1492- enabled: root.state == "visible" && (!root.lockedVisible || panel.highlightIndex >= -1)
1493+ enabled: root.state == "visible" || root.state == "drawer"
1494 visible: enabled
1495 onPressed: {
1496 mouse.accepted = false;
1497@@ -307,23 +326,61 @@
1498 }
1499 }
1500
1501- EdgeBarrier {
1502- id: edgeBarrier
1503- edge: Qt.LeftEdge
1504- target: parent
1505- enabled: root.available
1506- onPassed: { root.switchToNextState("visibleTemporary"); }
1507- material: Component {
1508- Item {
1509- Rectangle {
1510- width: parent.height
1511- height: parent.width
1512- rotation: -90
1513- anchors.centerIn: parent
1514- gradient: Gradient {
1515- GradientStop { position: 0.0; color: Qt.rgba(panel.color.r, panel.color.g, panel.color.b, .5)}
1516- GradientStop { position: 1.0; color: Qt.rgba(panel.color.r,panel.color.g,panel.color.b,0)}
1517- }
1518+ BackgroundBlur {
1519+ id: backgroundBlur
1520+ anchors.fill: parent
1521+ anchors.topMargin: root.inverted ? 0 : -root.topPanelHeight
1522+ visible: root.blurSource && drawer.x > -drawer.width
1523+ blurAmount: units.gu(6)
1524+ sourceItem: root.blurSource
1525+ blurRect: Qt.rect(panel.width,
1526+ root.topPanelHeight,
1527+ drawer.width + drawer.x - panel.width,
1528+ height - root.topPanelHeight)
1529+ cached: drawer.moving
1530+ }
1531+
1532+ Drawer {
1533+ id: drawer
1534+ objectName: "drawer"
1535+ anchors {
1536+ top: parent.top
1537+ topMargin: root.inverted ? root.topPanelHeight : 0
1538+ bottom: parent.bottom
1539+ right: parent.left
1540+ }
1541+ width: Math.min(root.width, units.gu(90)) * .9
1542+ panelWidth: panel.width
1543+ visible: x > -width
1544+
1545+ Behavior on anchors.rightMargin {
1546+ enabled: !dragArea.dragging && !launcherDragArea.drag.active && panel.animate && !drawer.draggingHorizontally
1547+ NumberAnimation {
1548+ duration: 300
1549+ easing.type: Easing.OutCubic
1550+ }
1551+ }
1552+
1553+ onApplicationSelected: {
1554+ root.hide();
1555+ root.launcherApplicationSelected(appId)
1556+ root.focus = false;
1557+ }
1558+
1559+ Keys.onEscapePressed: {
1560+ switchToNextState("");
1561+ root.focus = false;
1562+ }
1563+
1564+ onDragDistanceChanged: {
1565+ anchors.rightMargin = Math.max(-drawer.width, anchors.rightMargin + dragDistance);
1566+ }
1567+ onDraggingHorizontallyChanged: {
1568+ if (!draggingHorizontally) {
1569+ if (drawer.x < -units.gu(10)) {
1570+ root.hide();
1571+ } else {
1572+ root.openDrawer();
1573 }
1574 }
1575 }
1576@@ -332,7 +389,7 @@
1577 LauncherPanel {
1578 id: panel
1579 objectName: "launcherPanel"
1580- enabled: root.available && root.state == "visible" || root.state == "visibleTemporary"
1581+ enabled: root.available && (root.state == "visible" || root.state == "visibleTemporary" || root.state == "drawer")
1582 width: root.panelWidth
1583 anchors {
1584 top: parent.top
1585@@ -394,6 +451,38 @@
1586 }
1587 }
1588
1589+ EdgeBarrier {
1590+ id: edgeBarrier
1591+ edge: Qt.LeftEdge
1592+ target: parent
1593+ enabled: root.available
1594+ onProgressChanged: {
1595+ if (progress > .5 && root.state != "visibleTemporary" && root.state != "drawer" && root.state != "visible") {
1596+ root.switchToNextState("visibleTemporary");
1597+ }
1598+ }
1599+ onPassed: {
1600+ if (root.drawerEnabled) {
1601+ root.switchToNextState("drawer");
1602+ }
1603+ }
1604+
1605+ material: Component {
1606+ Item {
1607+ Rectangle {
1608+ width: parent.height
1609+ height: parent.width
1610+ rotation: -90
1611+ anchors.centerIn: parent
1612+ gradient: Gradient {
1613+ GradientStop { position: 0.0; color: Qt.rgba(panel.color.r, panel.color.g, panel.color.b, .5)}
1614+ GradientStop { position: 1.0; color: Qt.rgba(panel.color.r,panel.color.g,panel.color.b,0)}
1615+ }
1616+ }
1617+ }
1618+ }
1619+ }
1620+
1621 SwipeArea {
1622 id: dragArea
1623 objectName: "launcherDragArea"
1624@@ -405,19 +494,34 @@
1625 width: root.dragAreaWidth
1626 height: root.height
1627
1628+ function easeInOutCubic(t) { return t<.5 ? 4*t*t*t : (t-1)*(2*t-2)*(2*t-2)+1 }
1629+
1630 onDistanceChanged: {
1631- if (!dragging || launcher.state == "visible")
1632- return;
1633+ if (dragging && launcher.state != "visible" && launcher.state != "drawer") {
1634+ panel.x = -panel.width + Math.min(Math.max(0, distance), panel.width);
1635+ }
1636
1637- panel.x = -panel.width + Math.min(Math.max(0, distance), panel.width);
1638+ if (root.drawerEnabled && dragging && launcher.state != "drawer") {
1639+ var drawerHintDistance = panel.width + units.gu(1)
1640+ if (distance < drawerHintDistance) {
1641+ drawer.anchors.rightMargin = -Math.min(Math.max(0, distance), drawer.width);
1642+ } else {
1643+ var linearDrawerX = Math.min(Math.max(0, distance - drawerHintDistance), drawer.width);
1644+ var linearDrawerProgress = linearDrawerX / (drawer.width)
1645+ var easedDrawerProgress = easeInOutCubic(linearDrawerProgress);
1646+ drawer.anchors.rightMargin = -(drawerHintDistance + easedDrawerProgress * (drawer.width - drawerHintDistance));
1647+ }
1648+ }
1649 }
1650
1651 onDraggingChanged: {
1652 if (!dragging) {
1653 if (distance > panel.width / 2) {
1654- root.switchToNextState("visible")
1655- if (distance > minimizeDistance) {
1656- root.dash();
1657+ if (root.drawerEnabled && distance > panel.width * 3) {
1658+ root.switchToNextState("drawer")
1659+ root.focus = true;
1660+ } else {
1661+ root.switchToNextState("visible")
1662 }
1663 } else if (root.state === "") {
1664 // didn't drag far enough. rollback
1665@@ -434,6 +538,10 @@
1666 target: panel
1667 x: -root.panelWidth
1668 }
1669+ PropertyChanges {
1670+ target: drawer
1671+ anchors.rightMargin: 0
1672+ }
1673 },
1674 State {
1675 name: "visible"
1676@@ -441,6 +549,18 @@
1677 target: panel
1678 x: -root.x // so we never go past panelWidth, even when teased by tutorial
1679 }
1680+ PropertyChanges {
1681+ target: drawer
1682+ anchors.rightMargin: 0
1683+ }
1684+ },
1685+ State {
1686+ name: "drawer"
1687+ extend: "visible"
1688+ PropertyChanges {
1689+ target: drawer
1690+ anchors.rightMargin: -drawer.width + root.x // so we never go past panelWidth, even when teased by tutorial
1691+ }
1692 },
1693 State {
1694 name: "visibleTemporary"
1695
1696=== added file 'qml/Launcher/MoreAppsHeader.qml'
1697--- qml/Launcher/MoreAppsHeader.qml 1970-01-01 00:00:00 +0000
1698+++ qml/Launcher/MoreAppsHeader.qml 2016-12-07 18:01:28 +0000
1699@@ -0,0 +1,46 @@
1700+import QtQuick 2.4
1701+import Ubuntu.Components 1.3
1702+
1703+AbstractButton {
1704+ id: root
1705+
1706+ onClicked: {
1707+ // TODO: Make this point to the snappy store as soon as we stop landing to vivid
1708+ Qt.openUrlExternally("scope://com.canonical.scopes.clickstore")
1709+ }
1710+
1711+ UbuntuShape {
1712+ width: parent.width
1713+ height: parent.height - units.gu(1)
1714+ color: "#20ffffff"
1715+ aspect: UbuntuShape.Flat
1716+
1717+ Row {
1718+ anchors.fill: parent
1719+ anchors.margins: units.gu(1)
1720+ spacing: units.gu(1)
1721+
1722+ Icon {
1723+ height: units.gu(2.2)
1724+ width: height
1725+ name: "stock_application"
1726+ anchors.verticalCenter: parent.verticalCenter
1727+ color: "white"
1728+ }
1729+
1730+ Label {
1731+ text: i18n.tr("More apps in the store")
1732+ anchors.verticalCenter: parent.verticalCenter
1733+ fontSize: "small"
1734+ }
1735+
1736+ Icon {
1737+ height: units.gu(2.5)
1738+ width: height
1739+ anchors.verticalCenter: parent.verticalCenter
1740+ name: "go-next"
1741+ color: "white"
1742+ }
1743+ }
1744+ }
1745+}
1746
1747=== modified file 'qml/Shell.qml'
1748--- qml/Shell.qml 2016-11-29 09:39:56 +0000
1749+++ qml/Shell.qml 2016-12-07 18:01:28 +0000
1750@@ -278,8 +278,6 @@
1751
1752 dragAreaWidth: shell.edgeSize
1753 background: wallpaperResolver.background
1754- leftEdgeDragProgress: !greeter || greeter.locked || !tutorial.launcherLongSwipeEnabled ? 0 :
1755- Math.max(0, (launcher.dragDistance * (stage.width - launcher.panelWidth) / stage.width) - launcher.panelWidth)
1756
1757 applicationManager: ApplicationManager
1758 topLevelSurfaceList: topLevelSurfaceList
1759@@ -301,14 +299,12 @@
1760
1761 interactive: (!greeter || !greeter.shown)
1762 && panel.indicators.fullyClosed
1763- && launcher.progress == 0
1764 && !notifications.useModal
1765
1766 onInteractiveChanged: { if (interactive) { focus = true; } }
1767
1768 leftMargin: shell.usageScenario == "desktop" && !settings.autohideLauncher ? launcher.panelWidth: 0
1769 suspended: greeter.shown
1770- keepDashRunning: launcher.shown || launcher.dashSwipe
1771 altTabPressed: physicalKeysMapper.altTabPressed
1772 oskEnabled: shell.oskEnabled
1773 spreadEnabled: tutorial.spreadEnabled && (!greeter || (!greeter.hasLockedApp && !greeter.shown))
1774@@ -323,7 +319,7 @@
1775 topMargin: panel.panelHeight
1776 leftMargin: launcher.lockedVisible ? launcher.panelWidth : 0
1777 }
1778- z: notifications.useModal || panel.indicators.shown || wizard.active || tutorial.running ? overlay.z + 1 : overlay.z - 1
1779+ z: notifications.useModal || panel.indicators.shown || wizard.active || tutorial.running || launcher.drawerShown ? overlay.z + 1 : overlay.z - 1
1780 }
1781
1782 Loader {
1783@@ -345,7 +341,6 @@
1784 enabled: panel.indicators.fullyClosed // hides OSK when panel is open
1785 hides: [launcher, panel.indicators]
1786 tabletMode: shell.usageScenario != "phone"
1787- launcherOffset: launcher.progress
1788 forcedUnlock: wizard.active || shell.mode === "full-shell"
1789 background: wallpaperResolver.cachedBackground
1790 hasCustomBackground: wallpaperResolver.hasCustomBackground
1791@@ -434,19 +429,6 @@
1792 }
1793 }
1794
1795- function showDash() {
1796- if (greeter.notifyShowingDashFromDrag()) {
1797- launcher.fadeOut();
1798- }
1799-
1800- if (!greeter.locked && tutorial.launcherLongSwipeEnabled
1801- && (ApplicationManager.focusedApplicationId != "unity8-dash" || stage.spreadShown)) {
1802- ApplicationManager.requestFocusApplication("unity8-dash")
1803- launcher.fadeOut();
1804- stage.closeSpread();
1805- }
1806- }
1807-
1808 Item {
1809 id: overlay
1810 z: 10
1811@@ -497,15 +479,6 @@
1812 id: launcher
1813 objectName: "launcher"
1814
1815- /*
1816- * Since the Dash doesn't have the same controll over surfaces that the
1817- * Shell does, it can't slowly move the scope out of the way, as the shell
1818- * does with apps, and the dash is show instantly. This allows for some
1819- * leeway and prevents accidental home swipes.
1820- */
1821- readonly property real offset: shell.focusedApplicationId == "unity8-dash" ? units.gu(12) : 0
1822- readonly property bool dashSwipe: progress > offset
1823-
1824 anchors.top: parent.top
1825 anchors.topMargin: inverted ? 0 : panel.panelHeight
1826 anchors.bottom: parent.bottom
1827@@ -521,14 +494,11 @@
1828 superTabPressed: physicalKeysMapper.superTabPressed
1829 panelWidth: units.gu(settings.launcherWidth)
1830 lockedVisible: shell.usageScenario == "desktop" && !settings.autohideLauncher && !panel.fullscreenMode
1831+ blurSource: greeter.shown ? greeter : stages
1832+ topPanelHeight: panel.panelHeight
1833+ drawerEnabled: !greeter.shown
1834
1835 onShowDashHome: showHome()
1836- onDash: showDash()
1837- onDashSwipeChanged: {
1838- if (dashSwipe) {
1839- dash.setCurrentScope(0, false, true)
1840- }
1841- }
1842 onLauncherApplicationSelected: {
1843 greeter.notifyUserRequestedApp();
1844 shell.activateApplication(appId);
1845@@ -545,6 +515,12 @@
1846 }
1847
1848 GlobalShortcut {
1849+ shortcut: Qt.MetaModifier | Qt.Key_A
1850+ onTriggered: {
1851+ launcher.openDrawer(true);
1852+ }
1853+ }
1854+ GlobalShortcut {
1855 shortcut: Qt.AltModifier | Qt.Key_F1
1856 onTriggered: {
1857 launcher.openForKeyboardNavigation();
1858
1859=== modified file 'qml/Stage/Stage.qml'
1860--- qml/Stage/Stage.qml 2016-11-29 09:39:25 +0000
1861+++ qml/Stage/Stage.qml 2016-12-07 18:01:28 +0000
1862@@ -36,7 +36,6 @@
1863 property url background
1864 property int dragAreaWidth
1865 property bool interactive
1866- property bool keepDashRunning: true
1867 property real nativeHeight
1868 property real nativeWidth
1869 property QtObject orientations
1870@@ -50,7 +49,6 @@
1871
1872 // Configuration
1873 property string mode: "staged"
1874- property real leftEdgeDragProgress: 0
1875
1876 // Used by the tutorial code
1877 readonly property real rightEdgeDragProgress: rightEdgeDragArea.dragging ? rightEdgeDragArea.progress : 0 // How far left the stage has been dragged
1878@@ -415,7 +413,7 @@
1879 // in staged mode, when it switches to Windowed mode it will suddenly
1880 // resume all those apps at once. We might want to avoid that.
1881 value: root.mode === "windowed"
1882- || (isDash && root.keepDashRunning)
1883+ || isDash
1884 || (!root.suspended && model.application && priv.focusedAppDelegate &&
1885 (priv.focusedAppDelegate.appId === model.application.appId ||
1886 priv.mainStageAppId === model.application.appId ||
1887@@ -478,7 +476,7 @@
1888 visible: true
1889 blurRadius: 32
1890 brightness: .65
1891- opacity: MathUtils.linearAnimation(spreadItem.rightEdgeBreakPoint, 1, 0, 1, Math.max(rightEdgeDragArea.progress, edgeBarrier.progress))
1892+ opacity: MathUtils.linearAnimation(spreadItem.rightEdgeBreakPoint, 1, 0, 1, Math.max(rightEdgeDragArea.dragging ? rightEdgeDragArea.progress : 0, edgeBarrier.progress))
1893 }
1894 },
1895 State {
1896@@ -1061,7 +1059,6 @@
1897 sideStageX: sideStage.x
1898 itemIndex: appDelegate.itemIndex
1899 nextInStack: priv.nextInStack
1900- leftEdgeDragProgress: root.leftEdgeDragProgress
1901 }
1902
1903 StagedRightEdgeMaths {
1904@@ -1164,7 +1161,7 @@
1905 when: root.mode == "windowed" && (root.state == "windowedRightEdge" || rightEdgeFocusAnimation.running || hidingAnimation.running || edgeBarrier.progress > 0)
1906 PropertyChanges {
1907 target: windowedRightEdgeMaths
1908- progress: Math.max(rightEdgeDragArea.progress, edgeBarrier.progress)
1909+ progress: Math.max(rightEdgeDragArea.dragging ? rightEdgeDragArea.progress : 0, edgeBarrier.progress)
1910 }
1911 PropertyChanges {
1912 target: appDelegate
1913
1914=== modified file 'qml/Stage/StageMaths.qml'
1915--- qml/Stage/StageMaths.qml 2016-09-13 13:15:09 +0000
1916+++ qml/Stage/StageMaths.qml 2016-12-07 18:01:28 +0000
1917@@ -12,7 +12,6 @@
1918 property int sideStageWidth: 0
1919 property int sideStageX: sceneWidth
1920 property bool animateX: false
1921- property int leftEdgeDragProgress: 0
1922
1923 property int stage: ApplicationInfoInterface.MainStage
1924 property var thisDelegate: null
1925@@ -26,10 +25,6 @@
1926 // of the last focused order.
1927 readonly property int itemZ: {
1928 // only shuffle when we've got a main and side stage
1929- if (thisDelegate.isDash && thisDelegate != mainStageDelegate && leftEdgeDragProgress > 0) {
1930- return -1; // Keep the dash behind all other apps for the left edge gesture
1931- }
1932-
1933 if (!sideStageDelegate) return itemIndex;
1934
1935 // don't shuffle indexes greater than "actives or next"
1936@@ -64,12 +59,12 @@
1937
1938 property int itemX: {
1939 if (mainStageDelegate == thisDelegate) {
1940- return thisDelegate.isDash ? 0 : leftEdgeDragProgress;
1941+ return 0
1942 }
1943 if (sideStageDelegate == thisDelegate) {
1944 return sideStageX;
1945 }
1946- return thisDelegate.isDash && leftEdgeDragProgress > 0 ? 0 : sceneWidth;
1947+ return sceneWidth;
1948 }
1949 Behavior on itemX { enabled: root.animateX; UbuntuNumberAnimation {} }
1950
1951
1952=== modified file 'qml/Tutorial/TutorialLeftLong.qml'
1953--- qml/Tutorial/TutorialLeftLong.qml 2016-04-29 09:12:21 +0000
1954+++ qml/Tutorial/TutorialLeftLong.qml 2016-12-07 18:01:28 +0000
1955@@ -25,7 +25,7 @@
1956
1957 // Unlike other tutorials, this one can't be skipped before we show it, so
1958 // only set opacityOverride if we're already shown.
1959- opacityOverride: shown ? 1 - launcher.dragDistance / launcher.minimizeDistance : 1
1960+ opacityOverride: shown ? 1 - launcher.dragDistance / (launcher.panelWidth * 3) : 1
1961
1962 mouseArea {
1963 anchors.leftMargin: launcher.dragAreaWidth
1964
1965=== modified file 'tests/mocks/Unity/Launcher/CMakeLists.txt'
1966--- tests/mocks/Unity/Launcher/CMakeLists.txt 2016-10-28 12:08:59 +0000
1967+++ tests/mocks/Unity/Launcher/CMakeLists.txt 2016-12-07 18:01:28 +0000
1968@@ -1,7 +1,8 @@
1969-pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=10)
1970+pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=11)
1971
1972 include_directories(
1973 ${CMAKE_CURRENT_SOURCE_DIR}
1974+ ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher/
1975 )
1976
1977 set(MockLauncherModel_SOURCES
1978@@ -9,10 +10,13 @@
1979 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherItemInterface.h
1980 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherModelInterface.h
1981 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/QuickListModelInterface.h
1982+ ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/AppDrawerModelInterface.h
1983 plugin.cpp
1984 MockLauncherModel.cpp
1985 MockLauncherItem.cpp
1986 MockQuickListModel.cpp
1987+ MockAppDrawerModel.cpp
1988+ ${CMAKE_SOURCE_DIR}/plugins/Utils/applicationsfiltermodel.cpp
1989 )
1990
1991 add_library(MockLauncherPlugin MODULE ${MockLauncherModel_SOURCES})
1992
1993=== added file 'tests/mocks/Unity/Launcher/MockAppDrawerModel.cpp'
1994--- tests/mocks/Unity/Launcher/MockAppDrawerModel.cpp 1970-01-01 00:00:00 +0000
1995+++ tests/mocks/Unity/Launcher/MockAppDrawerModel.cpp 2016-12-07 18:01:28 +0000
1996@@ -0,0 +1,75 @@
1997+/*
1998+ * Copyright (C) 2016 Canonical, Ltd.
1999+ *
2000+ * This program is free software; you can redistribute it and/or modify
2001+ * it under the terms of the GNU General Public License as published by
2002+ * the Free Software Foundation; version 3.
2003+ *
2004+ * This program is distributed in the hope that it will be useful,
2005+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2006+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2007+ * GNU General Public License for more details.
2008+ *
2009+ * You should have received a copy of the GNU General Public License
2010+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2011+ */
2012+
2013+#include "MockAppDrawerModel.h"
2014+
2015+#include <QDebug>
2016+#include <QDateTime>
2017+
2018+MockAppDrawerModel::MockAppDrawerModel(QObject *parent):
2019+ AppDrawerModelInterface(parent)
2020+{
2021+ MockLauncherItem *item = new MockLauncherItem("dialer-app", "/usr/share/applications/dialer-app.desktop", "Dialer", "dialer-app", this);
2022+ m_list.append(item);
2023+ item = new MockLauncherItem("camera-app", "/usr/share/applications/camera-app.desktop", "Camera", "camera", this);
2024+ m_list.append(item);
2025+ item = new MockLauncherItem("camera-app2", "/usr/share/applications/camera-app2.desktop", "Camera2", "camera", this);
2026+ m_list.append(item);
2027+ item = new MockLauncherItem("gallery-app", "/usr/share/applications/gallery-app.desktop", "Gallery", "gallery", this);
2028+ m_list.append(item);
2029+ item = new MockLauncherItem("music-app", "/usr/share/applications/music-app.desktop", "Music", "soundcloud", this);
2030+ m_list.append(item);
2031+ item = new MockLauncherItem("facebook-webapp", "/usr/share/applications/facebook-webapp.desktop", "Facebook", "facebook", this);
2032+ m_list.append(item);
2033+ item = new MockLauncherItem("webbrowser-app", "/usr/share/applications/webbrowser-app.desktop", "Browser", "browser", this);
2034+ m_list.append(item);
2035+ item = new MockLauncherItem("twitter-webapp", "/usr/share/applications/twitter-webapp.desktop", "Twitter", "twitter", this);
2036+ m_list.append(item);
2037+ item = new MockLauncherItem("gmail-webapp", "/usr/share/applications/gmail-webapp.desktop", "GMail", "gmail", this);
2038+ m_list.append(item);
2039+ item = new MockLauncherItem("ubuntu-weather-app", "/usr/share/applications/ubuntu-weather-app.desktop", "Weather", "weather", this);
2040+ m_list.append(item);
2041+ item = new MockLauncherItem("notes-app", "/usr/share/applications/notes-app.desktop", "Notepad", "notepad", this);
2042+ m_list.append(item);
2043+ item = new MockLauncherItem("calendar-app", "/usr/share/applications/calendar-app.desktop","Calendar", "calendar", this);
2044+ m_list.append(item);
2045+ item = new MockLauncherItem("libreoffice", "/usr/share/applications/libreoffice.desktop","Libre Office", "libreoffice", this);
2046+ m_list.append(item);
2047+ qDebug() << "mock model created";
2048+
2049+ qsrand(QDateTime::currentMSecsSinceEpoch() / 1000);
2050+}
2051+
2052+int MockAppDrawerModel::rowCount(const QModelIndex &parent) const
2053+{
2054+ return m_list.count();
2055+}
2056+
2057+QVariant MockAppDrawerModel::data(const QModelIndex &index, int role) const
2058+{
2059+ switch (role) {
2060+ case RoleAppId:
2061+ return m_list.at(index.row())->appId();
2062+ case RoleName:
2063+ return m_list.at(index.row())->name();
2064+ case RoleIcon:
2065+ return m_list.at(index.row())->icon();
2066+ case RoleUsage:
2067+ return qrand();
2068+ }
2069+
2070+ return QVariant();
2071+}
2072
2073=== added file 'tests/mocks/Unity/Launcher/MockAppDrawerModel.h'
2074--- tests/mocks/Unity/Launcher/MockAppDrawerModel.h 1970-01-01 00:00:00 +0000
2075+++ tests/mocks/Unity/Launcher/MockAppDrawerModel.h 2016-12-07 18:01:28 +0000
2076@@ -0,0 +1,32 @@
2077+/*
2078+ * Copyright (C) 2016 Canonical, Ltd.
2079+ *
2080+ * This program is free software; you can redistribute it and/or modify
2081+ * it under the terms of the GNU General Public License as published by
2082+ * the Free Software Foundation; version 3.
2083+ *
2084+ * This program is distributed in the hope that it will be useful,
2085+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2086+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2087+ * GNU General Public License for more details.
2088+ *
2089+ * You should have received a copy of the GNU General Public License
2090+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2091+ */
2092+
2093+#include <unity/shell/launcher/AppDrawerModelInterface.h>
2094+
2095+#include "MockLauncherItem.h"
2096+
2097+class MockAppDrawerModel: public AppDrawerModelInterface
2098+{
2099+ Q_OBJECT
2100+public:
2101+ MockAppDrawerModel(QObject* parent = nullptr);
2102+
2103+ int rowCount(const QModelIndex &parent) const override;
2104+ QVariant data(const QModelIndex &index, int role) const override;
2105+
2106+private:
2107+ QList<MockLauncherItem*> m_list;
2108+};
2109
2110=== modified file 'tests/mocks/Unity/Launcher/MockLauncherItem.cpp'
2111--- tests/mocks/Unity/Launcher/MockLauncherItem.cpp 2016-05-13 11:28:56 +0000
2112+++ tests/mocks/Unity/Launcher/MockLauncherItem.cpp 2016-12-07 18:01:28 +0000
2113@@ -67,6 +67,11 @@
2114 return m_icon;
2115 }
2116
2117+QStringList MockLauncherItem::keywords() const
2118+{
2119+ return m_keywords;
2120+}
2121+
2122 bool MockLauncherItem::pinned() const
2123 {
2124 return m_pinned;
2125@@ -200,3 +205,11 @@
2126 {
2127 return m_quickList;
2128 }
2129+
2130+void MockLauncherItem::setKeywords(const QStringList &keywords)
2131+{
2132+ if (m_keywords != keywords) {
2133+ m_keywords = keywords;
2134+ Q_EMIT keywordsChanged(keywords);
2135+ }
2136+}
2137
2138=== modified file 'tests/mocks/Unity/Launcher/MockLauncherItem.h'
2139--- tests/mocks/Unity/Launcher/MockLauncherItem.h 2016-05-10 15:51:00 +0000
2140+++ tests/mocks/Unity/Launcher/MockLauncherItem.h 2016-12-07 18:01:28 +0000
2141@@ -22,6 +22,8 @@
2142
2143 #include <unity/shell/launcher/LauncherItemInterface.h>
2144
2145+#include <QStringList>
2146+
2147 class MockQuickListModel;
2148
2149 using namespace unity::shell::launcher;
2150@@ -37,6 +39,7 @@
2151 QString desktopFile() const;
2152 QString name() const override;
2153 QString icon() const override;
2154+ QStringList keywords() const override;
2155
2156 bool pinned() const override;
2157 bool running() const override;
2158@@ -51,6 +54,7 @@
2159 unity::shell::launcher::QuickListModelInterface *quickList() const override;
2160
2161 private:
2162+ void setKeywords(const QStringList &keywords);
2163 void setPinned(bool pinned);
2164 void setRunning(bool running);
2165 void setRecent(bool recent);
2166@@ -65,6 +69,7 @@
2167 QString m_desktopFile;
2168 QString m_name;
2169 QString m_icon;
2170+ QStringList m_keywords;
2171 bool m_pinned;
2172 bool m_running;
2173 bool m_recent;
2174@@ -77,6 +82,7 @@
2175 MockQuickListModel *m_quickList;
2176
2177 friend class MockLauncherModel;
2178+ friend class MockAppDrawerModel;
2179 };
2180
2181 #endif // MOCKLAUNCHERITEM_H
2182
2183=== modified file 'tests/mocks/Unity/Launcher/MockLauncherModel.cpp'
2184--- tests/mocks/Unity/Launcher/MockLauncherModel.cpp 2016-06-17 01:13:55 +0000
2185+++ tests/mocks/Unity/Launcher/MockLauncherModel.cpp 2016-12-07 18:01:28 +0000
2186@@ -36,6 +36,9 @@
2187 item = new MockLauncherItem("camera-app2", "/usr/share/applications/camera-app2.desktop", "Camera2", "camera", this);
2188 item->setPinned(true);
2189 m_list.append(item);
2190+ item = new MockLauncherItem("camera-app3", "/usr/share/applications/camera-app2.desktop", "Camera2", "camera", this);
2191+ item->setPinned(true);
2192+ m_list.append(item);
2193 item = new MockLauncherItem("gallery-app", "/usr/share/applications/gallery-app.desktop", "Gallery", "gallery", this);
2194 item->setProgress(50);
2195 item->setCountVisible(true);
2196
2197=== modified file 'tests/mocks/Unity/Launcher/plugin.cpp'
2198--- tests/mocks/Unity/Launcher/plugin.cpp 2013-08-19 15:10:58 +0000
2199+++ tests/mocks/Unity/Launcher/plugin.cpp 2016-12-07 18:01:28 +0000
2200@@ -21,9 +21,11 @@
2201 #include "MockLauncherModel.h"
2202 #include "MockLauncherItem.h"
2203 #include "MockQuickListModel.h"
2204+#include "MockAppDrawerModel.h"
2205
2206 #include <unity/shell/launcher/LauncherModelInterface.h>
2207 #include <unity/shell/launcher/LauncherItemInterface.h>
2208+#include <unity/shell/launcher/AppDrawerModelInterface.h>
2209
2210 #include <QtQml/qqml.h>
2211
2212@@ -41,8 +43,10 @@
2213 qmlRegisterUncreatableType<LauncherModelInterface>(uri, 0, 1, "LauncherModelInterface", "Abstract Interface. Cannot be instantiated.");
2214 qmlRegisterUncreatableType<LauncherItemInterface>(uri, 0, 1, "LauncherItemInterface", "Abstract Interface. Cannot be instantiated.");
2215 qmlRegisterUncreatableType<QuickListModelInterface>(uri, 0, 1, "QuickListModelInterface", "Abstract Interface. Cannot be instantiated.");
2216+ qmlRegisterUncreatableType<AppDrawerModelInterface>(uri, 0, 1, "AppDrawerModelInterface", "Abstract Interface. Cannot be instantiated.");
2217
2218 qmlRegisterSingletonType<MockLauncherModel>(uri, 0, 1, "LauncherModel", modelProvider);
2219 qmlRegisterUncreatableType<MockLauncherItem>(uri, 0, 1, "LauncherItem", "Can't create LauncherItems in QML. Get them from the LauncherModel");
2220 qmlRegisterUncreatableType<MockQuickListModel>(uri, 0, 1, "QuickListModel", "Can't create QuickLists in QML. Get them from the LauncherItems");
2221+ qmlRegisterType<MockAppDrawerModel>(uri, 0, 1, "AppDrawerModel");
2222 }
2223
2224=== modified file 'tests/mocks/Utils/CMakeLists.txt'
2225--- tests/mocks/Utils/CMakeLists.txt 2016-06-29 18:05:44 +0000
2226+++ tests/mocks/Utils/CMakeLists.txt 2016-12-07 18:01:28 +0000
2227@@ -24,11 +24,15 @@
2228 ${CMAKE_SOURCE_DIR}/plugins/Utils/inputeventgenerator.cpp
2229 ${CMAKE_SOURCE_DIR}/plugins/Utils/deviceconfigparser.cpp
2230 ${CMAKE_SOURCE_DIR}/plugins/Utils/globalfunctions.cpp
2231+ ${CMAKE_SOURCE_DIR}/plugins/Utils/appdrawerproxymodel.cpp
2232 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationManagerInterface.h
2233 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/ApplicationInfoInterface.h
2234 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/MirSurfaceInterface.h
2235 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/MirSurfaceListInterface.h
2236 ${APPLICATION_API_INCLUDEDIR}/unity/shell/application/Mir.h
2237+ ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/AppDrawerModelInterface.h
2238+ ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherModelInterface.h
2239+ ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherItemInterface.h
2240 constants.cpp
2241 plugin.cpp
2242 windowstatestorage.cpp
2243
2244=== modified file 'tests/mocks/Utils/plugin.cpp'
2245--- tests/mocks/Utils/plugin.cpp 2016-06-28 20:38:00 +0000
2246+++ tests/mocks/Utils/plugin.cpp 2016-12-07 18:01:28 +0000
2247@@ -40,6 +40,7 @@
2248 #include <inputeventgenerator.h>
2249 #include <deviceconfigparser.h>
2250 #include <globalfunctions.h>
2251+#include <appdrawerproxymodel.h>
2252
2253 static QObject *createWindowStateStorage(QQmlEngine *engine, QJSEngine *scriptEngine)
2254 {
2255@@ -82,4 +83,5 @@
2256 qmlRegisterType<DeviceConfigParser>(uri, 0, 1, "DeviceConfigParser");
2257 qmlRegisterSingletonType<GlobalFunctions>(uri, 0, 1, "Functions", createGlobalFunctions);
2258 qmlRegisterType<URLDispatcher>(uri, 0, 1, "URLDispatcher");
2259+ qmlRegisterType<AppDrawerProxyModel>(uri, 0, 1, "AppDrawerProxyModel");
2260 }
2261
2262=== modified file 'tests/plugins/Greeter/Unity/Launcher/CMakeLists.txt'
2263--- tests/plugins/Greeter/Unity/Launcher/CMakeLists.txt 2016-10-28 12:08:59 +0000
2264+++ tests/plugins/Greeter/Unity/Launcher/CMakeLists.txt 2016-12-07 18:01:28 +0000
2265@@ -1,4 +1,4 @@
2266-pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=10)
2267+pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=11)
2268
2269 include_directories(
2270 ${CMAKE_CURRENT_SOURCE_DIR}
2271
2272=== modified file 'tests/plugins/Unity/Launcher/CMakeLists.txt'
2273--- tests/plugins/Unity/Launcher/CMakeLists.txt 2016-10-28 12:08:59 +0000
2274+++ tests/plugins/Unity/Launcher/CMakeLists.txt 2016-12-07 18:01:28 +0000
2275@@ -1,5 +1,5 @@
2276 pkg_check_modules(GSETTINGS_QT REQUIRED gsettings-qt)
2277-pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=10)
2278+pkg_check_modules(LAUNCHER_API REQUIRED unity-shell-launcher=11)
2279
2280 include_directories(
2281 ${CMAKE_CURRENT_SOURCE_DIR}
2282@@ -30,6 +30,7 @@
2283 ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher/quicklistmodel.cpp
2284 ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher/dbusinterface.cpp
2285 ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher/quicklistentry.cpp
2286+ ${CMAKE_SOURCE_DIR}/plugins/Unity/Launcher/ualwrapper.cpp
2287 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherItemInterface.h
2288 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/LauncherModelInterface.h
2289 ${LAUNCHER_API_INCLUDEDIR}/unity/shell/launcher/QuickListModelInterface.h
2290
2291=== modified file 'tests/qmltests/CMakeLists.txt'
2292--- tests/qmltests/CMakeLists.txt 2016-09-22 14:19:36 +0000
2293+++ tests/qmltests/CMakeLists.txt 2016-12-07 18:01:28 +0000
2294@@ -71,6 +71,7 @@
2295 add_unity8_qmltest(Greeter NarrowView)
2296 add_unity8_qmltest(Greeter WideView)
2297 add_unity8_qmltest(Launcher Launcher)
2298+add_unity8_qmltest(Launcher Drawer)
2299 add_unity8_qmltest(Notifications Notifications)
2300 add_unity8_qmltest(Notifications VisualSnapDecisionsQueue)
2301 add_unity8_qmltest(Notifications OptionToggle)
2302
2303=== modified file 'tests/qmltests/Dash/tst_DashShell.qml'
2304--- tests/qmltests/Dash/tst_DashShell.qml 2016-07-08 20:44:09 +0000
2305+++ tests/qmltests/Dash/tst_DashShell.qml 2016-12-07 18:01:28 +0000
2306@@ -112,34 +112,5 @@
2307 mouseClick(buttonShowDashHome);
2308 tryCompare(dashContentList, "currentIndex", 0);
2309 }
2310-
2311- function test_setShortLauncherMoveResetNonActiveDash() {
2312- var dashContentList = findChild(dash, "dashContentList");
2313- var startX = dash.width - units.gu(1);
2314- var startY = dash.height / 2;
2315- var stopX = units.gu(1)
2316- var stopY = startY;
2317- waitForRendering(dashContentList);
2318- touchFlick(dash, startX, startY, stopX, stopY);
2319- touchFlick(dash, startX, startY, stopX, stopY);
2320- compare(dashContentList.currentIndex, 2, "Could not flick to scope id 2");
2321-
2322- // Pretend the dash is not active
2323- dash.windowActive = false;
2324-
2325- // Flick the greeter away
2326- var startX = shell.width - units.gu(1);
2327- var startY = shell.height / 2;
2328- var stopX = units.gu(1)
2329- var stopY = startY;
2330- touchFlick(shell, startX, startY, stopX, stopY);
2331-
2332- var greeter = findChild(shell, "greeter");
2333- tryCompare(greeter, "shown", false);
2334-
2335- // Now do a small launcher movement
2336- touchFlick(shell, stopX, startY, startX, stopY);
2337- compare(dashContentList.currentIndex, 0, "Small launcher move did not reset dash on non active window");
2338- }
2339 }
2340 }
2341
2342=== added file 'tests/qmltests/Launcher/tst_Drawer.qml'
2343--- tests/qmltests/Launcher/tst_Drawer.qml 1970-01-01 00:00:00 +0000
2344+++ tests/qmltests/Launcher/tst_Drawer.qml 2016-12-07 18:01:28 +0000
2345@@ -0,0 +1,245 @@
2346+/*
2347+ * Copyright 2013-2016 Canonical Ltd.
2348+ *
2349+ * This program is free software; you can redistribute it and/or modify
2350+ * it under the terms of the GNU General Public License as published by
2351+ * the Free Software Foundation; version 3.
2352+ *
2353+ * This program is distributed in the hope that it will be useful,
2354+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2355+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2356+ * GNU General Public License for more details.
2357+ *
2358+ * You should have received a copy of the GNU General Public License
2359+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2360+ */
2361+
2362+import QtQuick 2.4
2363+import QtQuick.Layouts 1.1
2364+import Ubuntu.Components 1.3
2365+import ".."
2366+import "../../../qml/Launcher"
2367+import Unity.Launcher 0.1
2368+import Utils 0.1 // For EdgeBarrierSettings
2369+import Unity.Test 0.1
2370+
2371+StyledItem {
2372+ id: root
2373+ theme.name: "Ubuntu.Components.Themes.SuruDark"
2374+
2375+ width: units.gu(140)
2376+ height: units.gu(70)
2377+ Rectangle {
2378+ anchors.fill: parent
2379+ color: UbuntuColors.graphite // something neither white nor black
2380+ }
2381+
2382+ Launcher {
2383+ id: launcher
2384+ x: 0
2385+ y: 0
2386+ width: units.gu(40)
2387+ height: root.height
2388+
2389+ lockedVisible: lockedVisibleCheckBox.checked
2390+
2391+ property string lastSelectedApplication
2392+ onLauncherApplicationSelected: {
2393+ lastSelectedApplication = appId
2394+ }
2395+
2396+ Component.onCompleted: {
2397+ launcher.focus = true
2398+ edgeBarrierControls.target = testCase.findChild(this, "edgeBarrierController");
2399+ }
2400+ }
2401+
2402+ ColumnLayout {
2403+ anchors { bottom: parent.bottom; right: parent.right; margins: units.gu(1) }
2404+ spacing: units.gu(1)
2405+ width: childrenRect.width
2406+
2407+ RowLayout {
2408+ CheckBox {
2409+ id: lockedVisibleCheckBox
2410+ checked: false
2411+ }
2412+ Label {
2413+ text: "Launcher always visible"
2414+ }
2415+ }
2416+
2417+ Slider {
2418+ id: widthSlider
2419+ Layout.fillWidth: true
2420+ minimumValue: 6
2421+ maximumValue: 12
2422+ value: 10
2423+ }
2424+
2425+ MouseTouchEmulationCheckbox {}
2426+
2427+ EdgeBarrierControls {
2428+ id: edgeBarrierControls
2429+ text: "Drag here to pull out launcher"
2430+ onDragged: { launcher.pushEdge(amount); }
2431+ }
2432+ }
2433+
2434+ UnityTestCase {
2435+ id: testCase
2436+ when: windowShown
2437+ name: "Drawer"
2438+
2439+ function dragDrawerIntoView() {
2440+ var startX = launcher.dragAreaWidth/2;
2441+ var startY = launcher.height/2;
2442+ touchFlick(launcher,
2443+ startX, startY,
2444+ startX+units.gu(35), startY);
2445+
2446+ var drawer = findChild(launcher, "drawer");
2447+ verify(!!drawer);
2448+
2449+ // wait until it gets fully extended
2450+ // a tryCompare doesn't work since
2451+ // compare(-0.000005917593600024418, 0);
2452+ // is true and in this case we want exactly 0 or will have pain later on
2453+ tryCompareFunction( function(){ return drawer.x === 0; }, true );
2454+ tryCompare(launcher, "state", "drawer");
2455+ tryCompare(launcher, "drawerShown", true);
2456+ }
2457+
2458+ function revealByEdgePush() {
2459+ // Place the mouse against the window/screen edge and push beyond the barrier threshold
2460+ // If the mouse did not move between two revealByEdgePush(), we need it to move out the
2461+ // area to make sure we're not just accumulating to the previous push
2462+ mouseMove(root, root.width, root.height / 2);
2463+ mouseMove(root, 1, root.height / 2);
2464+
2465+ launcher.pushEdge(EdgeBarrierSettings.pushThreshold * 1.1);
2466+
2467+ var drawer = findChild(launcher, "drawer");
2468+ verify(!!drawer);
2469+
2470+ // wait until it gets fully extended
2471+ tryCompare(drawer, "x", 0);
2472+ tryCompare(launcher, "state", "drawer");
2473+ tryCompare(launcher, "drawerShown", true);
2474+ }
2475+
2476+ function init() {
2477+ launcher.lastSelectedApplication = "";
2478+ launcher.lockedVisible = false;
2479+ launcher.hide();
2480+ var drawer = findChild(launcher, "drawer");
2481+ tryCompare(drawer, "x", -drawer.width);
2482+ }
2483+
2484+ function test_revealByEdgeDrag() {
2485+ dragDrawerIntoView();
2486+ }
2487+
2488+ function test_revealByEdgePush_data() {
2489+ return [
2490+ { tag: "autohide launcher", autohide: true },
2491+ { tag: "locked launcher", autohide: false }
2492+ ]
2493+ }
2494+
2495+ function test_revealByEdgePush(data) {
2496+ launcher.lockedVisible = !data.autohide;
2497+
2498+ var panel = findChild(launcher, "launcherPanel");
2499+ tryCompare(panel, "x", data.autohide ? -panel.width : 0);
2500+ tryCompare(launcher, "state", data.autohide ? "" : "visible");
2501+ waitForRendering(launcher)
2502+
2503+ revealByEdgePush();
2504+ }
2505+
2506+ function test_hideByDraggingDrawer_data() {
2507+ return [
2508+ {tag: "autohide", autohide: true, endState: ""},
2509+ {tag: "locked", autohide: false, endState: "visible"}
2510+ ]
2511+ }
2512+
2513+ function test_hideByDraggingDrawer(data) {
2514+ launcher.lockedVisible = !data.autohide;
2515+
2516+ dragDrawerIntoView();
2517+ waitForRendering(launcher);
2518+
2519+ var drawer = findChild(launcher, "drawer");
2520+
2521+ mouseFlick(root, drawer.width - units.gu(1), drawer.height / 2, units.gu(2), drawer.height / 2, true, true);
2522+
2523+ tryCompare(drawer.anchors, "rightMargin", 0);
2524+ tryCompare(launcher, "state", data.endState);
2525+ launcher.lockedVisible = false;
2526+ }
2527+
2528+ function test_hideByClickingOutside() {
2529+ dragDrawerIntoView();
2530+
2531+ var drawer = findChild(launcher, "drawer");
2532+
2533+ mouseClick(root, drawer.width + units.gu(1), root.height / 2);
2534+
2535+ tryCompare(launcher, "state", "");
2536+ }
2537+
2538+ function test_launchAppFromDrawer() {
2539+ dragDrawerIntoView();
2540+
2541+ var drawerList = findChild(launcher, "drawerItemList");
2542+ var dialerApp = findChild(drawerList, "drawerItem_dialer-app");
2543+ mouseClick(dialerApp, dialerApp.width / 2, dialerApp.height / 2);
2544+
2545+ tryCompare(launcher, "lastSelectedApplication", "dialer-app");
2546+
2547+ tryCompare(launcher, "state", "");
2548+ }
2549+
2550+ function test_launcherGivesUpFocusAfterLaunchingFromDrawer() {
2551+ dragDrawerIntoView();
2552+
2553+ tryCompare(launcher, "focus", true);
2554+
2555+ var drawerList = findChild(launcher, "drawerItemList");
2556+ var dialerApp = findChild(drawerList, "drawerItem_dialer-app");
2557+ mouseClick(dialerApp, dialerApp.width / 2, dialerApp.height / 2);
2558+
2559+ tryCompare(launcher, "focus", false);
2560+ }
2561+
2562+ function test_drawerDisabled() {
2563+ launcher.drawerEnabled = false;
2564+
2565+ var startX = launcher.dragAreaWidth/2;
2566+ var startY = launcher.height/2;
2567+ touchFlick(launcher,
2568+ startX, startY,
2569+ startX+units.gu(35), startY);
2570+
2571+ var drawer = findChild(launcher, "drawer");
2572+ verify(!!drawer);
2573+
2574+ tryCompare(launcher, "state", "visible");
2575+ tryCompare(launcher, "drawerShown", false);
2576+
2577+ launcher.drawerEnabled = true;
2578+ }
2579+
2580+ function test_search() {
2581+ compare(launcher.lastSelectedApplication, "");
2582+
2583+ launcher.openDrawer(true)
2584+ typeString("cam");
2585+ keyClick(Qt.Key_Enter);
2586+
2587+ compare(launcher.lastSelectedApplication, "camera-app");
2588+ }
2589+ }
2590+}
2591
2592=== modified file 'tests/qmltests/Launcher/tst_Launcher.qml'
2593--- tests/qmltests/Launcher/tst_Launcher.qml 2016-11-24 16:06:15 +0000
2594+++ tests/qmltests/Launcher/tst_Launcher.qml 2016-12-07 18:01:28 +0000
2595@@ -322,7 +322,7 @@
2596 function revealByEdgePush() {
2597 // Place the mouse against the window/screen edge and push beyond the barrier threshold
2598 mouseMove(root, 1, root.height / 2);
2599- launcher.pushEdge(EdgeBarrierSettings.pushThreshold * 1.1);
2600+ launcher.pushEdge(EdgeBarrierSettings.pushThreshold * .6);
2601
2602 var panel = findChild(launcher, "launcherPanel");
2603 verify(!!panel);
2604
2605=== modified file 'tests/qmltests/Stage/tst_PhoneStage.qml'
2606--- tests/qmltests/Stage/tst_PhoneStage.qml 2016-10-08 16:45:37 +0000
2607+++ tests/qmltests/Stage/tst_PhoneStage.qml 2016-12-07 18:01:28 +0000
2608@@ -334,32 +334,6 @@
2609 tryCompare(firstApp, "focused", true);
2610 }
2611
2612- function test_leftEdge_data() {
2613- return [
2614- { tag: "normal", inSpread: false, leftEdgeDragWidth: units.gu(20), shouldMoveApp: true },
2615- { tag: "inSpread", inSpread: true, leftEdgeDragWidth: units.gu(5), shouldMoveApp: false }
2616- ]
2617- }
2618-
2619- function test_leftEdge(data) {
2620- addApps(2);
2621-
2622- if (data.inSpread) {
2623- performEdgeSwipeToShowAppSpread();
2624- }
2625-
2626- var focusedDelegate = findChild(stage, "appDelegate_" + topLevelSurfaceList.idAt(0));
2627- var currentX = focusedDelegate.x;
2628-
2629- stage.leftEdgeDragProgress = data.leftEdgeDragWidth;
2630-
2631- tryCompare(focusedDelegate, "x", data.shouldMoveApp ? data.leftEdgeDragWidth : currentX);
2632-
2633- stage.leftEdgeDragProgress = 0;
2634-
2635- tryCompare(focusedDelegate, "x", currentX);
2636- }
2637-
2638 function test_focusedAppIsTheOnlyRunningApp() {
2639 addApps(2);
2640
2641
2642=== modified file 'tests/qmltests/tst_OrientedShell.qml'
2643--- tests/qmltests/tst_OrientedShell.qml 2016-11-14 01:39:43 +0000
2644+++ tests/qmltests/tst_OrientedShell.qml 2016-12-07 18:01:28 +0000
2645@@ -999,7 +999,7 @@
2646 var rotationStates = findInvisibleChild(orientedShell, "rotationStates");
2647 waitUntilTransitionsEnd(rotationStates);
2648
2649- performLeftEdgeSwipeToSwitchToDash();
2650+ ApplicationManager.requestFocusApplication("unity8-dash");
2651
2652 // Should be back to portrait
2653 tryCompare(shell, "transformRotationAngle", 0);
2654@@ -1391,18 +1391,6 @@
2655 waitUntilTransitionsEnd(rotationStates);
2656 }
2657
2658- function performLeftEdgeSwipeToSwitchToDash() {
2659- var swipeLength = shell.width * 0.7;
2660-
2661- var touchStartX = 1;
2662- var touchStartY = shell.height / 2;
2663- touchFlick(shell,
2664- touchStartX, touchStartY,
2665- touchStartX + swipeLength, touchStartY);
2666-
2667- tryCompare(ApplicationManager, "focusedApplicationId", "unity8-dash");
2668- }
2669-
2670 function performEdgeSwipeToSwitchToPreviousApp() {
2671 // swipe just enough to ensure an app switch action.
2672 // If we swipe too much we will trigger the spread mode
2673
2674=== modified file 'tests/qmltests/tst_Shell.qml'
2675--- tests/qmltests/tst_Shell.qml 2016-11-22 17:00:33 +0000
2676+++ tests/qmltests/tst_Shell.qml 2016-12-07 18:01:28 +0000
2677@@ -605,38 +605,6 @@
2678 compare(ApplicationManager.get(0).appId, "unity8-dash");
2679 }
2680
2681- function test_phoneLeftEdgeDrag_data() {
2682- return [
2683- {tag: "without launcher",
2684- revealLauncher: false, swipeLength: units.gu(30), appHides: true, focusedApp: "dialer-app",
2685- launcherHides: true, greeterShown: false},
2686-
2687- {tag: "with launcher",
2688- revealLauncher: true, swipeLength: units.gu(30), appHides: true, focusedApp: "dialer-app",
2689- launcherHides: true, greeterShown: false},
2690-
2691- {tag: "small swipe",
2692- revealLauncher: false, swipeLength: units.gu(25), appHides: false, focusedApp: "dialer-app",
2693- launcherHides: false, greeterShown: false},
2694-
2695- {tag: "long swipe",
2696- revealLauncher: false, swipeLength: units.gu(30), appHides: true, focusedApp: "dialer-app",
2697- launcherHides: true, greeterShown: false},
2698-
2699- {tag: "small swipe with greeter",
2700- revealLauncher: false, swipeLength: units.gu(25), appHides: false, focusedApp: "dialer-app",
2701- launcherHides: false, greeterShown: true},
2702-
2703- {tag: "long swipe with greeter",
2704- revealLauncher: false, swipeLength: units.gu(30), appHides: true, focusedApp: "dialer-app",
2705- launcherHides: true, greeterShown: true},
2706-
2707- {tag: "swipe over dash",
2708- revealLauncher: false, swipeLength: units.gu(30), appHides: true, focusedApp: "unity8-dash",
2709- launcherHides: false, greeterShown: false},
2710- ];
2711- }
2712-
2713 function test_snapDecisionDismissalReturnsFocus() {
2714 loadShell("phone");
2715 swipeAwayGreeter();
2716@@ -701,80 +669,6 @@
2717 mockNotificationsModel.append(n)
2718 }
2719
2720- function test_phoneLeftEdgeDrag(data) {
2721- loadShell("phone");
2722- swipeAwayGreeter();
2723- dragLauncherIntoView();
2724- var appSurfaceId = topLevelSurfaceList.nextId;
2725- tapOnAppIconInLauncher();
2726- waitUntilAppWindowIsFullyLoaded(appSurfaceId);
2727-
2728- var greeter = findChild(shell, "greeter");
2729- if (data.greeterShown) {
2730- showGreeter();
2731- }
2732-
2733- if (data.revealLauncher) {
2734- dragLauncherIntoView();
2735- }
2736-
2737- swipeFromLeftEdge(data.swipeLength);
2738- if (data.appHides) {
2739- waitUntilDashIsFocused();
2740- tryCompare(greeter, "shown", false);
2741- } else {
2742- tryCompare(greeter, "fullyShown", data.greeterShown);
2743- }
2744-
2745- var launcher = findChild(shell, "launcherPanel");
2746- tryCompare(launcher, "x", data.launcherHides ? -launcher.width : 0)
2747-
2748- //FIXME: This check fails. Don't understand the rationale behind it.
2749- /*
2750- // Make sure the helper for sliding out the launcher wasn't touched. We want to fade it out here.
2751- var animateTimer = findInvisibleChild(shell, "animateTimer");
2752- compare(animateTimer.nextState, "visible");
2753- */
2754- }
2755-
2756- function test_tabletLeftEdgeDrag_data() {
2757- return [
2758- {tag: "without password", user: "no-password", loggedIn: true},
2759- {tag: "with password", user: "has-password", loggedIn: false},
2760- ]
2761- }
2762-
2763- function test_tabletLeftEdgeDrag(data) {
2764- setLightDMMockMode("full");
2765- loadShell("tablet");
2766-
2767- selectUser(data.user)
2768-
2769- swipeFromLeftEdge(shell.width * 0.75)
2770- wait(500) // to give time to handle dash() signal from Launcher
2771- confirmLoggedIn(data.loggedIn)
2772- }
2773-
2774- function test_longLeftEdgeSwipeTakesToAppsAndResetSearchString() {
2775- loadShell("phone");
2776- swipeAwayGreeter();
2777- dragLauncherIntoView();
2778- dashCommunicatorSpy.clear();
2779-
2780- var appSurfaceId = topLevelSurfaceList.nextId;
2781- tapOnAppIconInLauncher();
2782- waitUntilAppWindowIsFullyLoaded(appSurfaceId);
2783-
2784- tryCompareFunction(function() { return ApplicationManager.focusedApplicationId !== "unity8-dash"; }, true);
2785-
2786- //Long left swipe
2787- swipeFromLeftEdge(units.gu(30));
2788-
2789- tryCompare(ApplicationManager, "focusedApplicationId", "unity8-dash");
2790-
2791- compare(dashCommunicatorSpy.count, 1);
2792- }
2793-
2794 function test_ClickUbuntuIconInLauncherTakesToAppsAndResetSearchString() {
2795 loadShell("phone");
2796 swipeAwayGreeter();
2797@@ -913,39 +807,6 @@
2798 LightDM.Users.mockMode = mode;
2799 }
2800
2801- /*
2802- Regression test for bug https://bugs.launchpad.net/touch-preview-images/+bug/1193419
2803-
2804- When the user minimizes an application (left-edge swipe) he should always end up in the
2805- "Applications" scope view.
2806-
2807- Steps:
2808- - reveal launcher and launch an app that covers the dash
2809- - perform long left edge swipe to go minimize the app and go back to the dash.
2810- - verify the setCurrentScope() D-Bus call to the dash has been called for the correct scope id.
2811- */
2812- function test_minimizingAppTakesToDashApps() {
2813- loadShell("phone");
2814- swipeAwayGreeter();
2815- dragLauncherIntoView();
2816-
2817- // Launch an app from the launcher
2818- var appSurfaceId = topLevelSurfaceList.nextId;
2819- tapOnAppIconInLauncher();
2820- waitUntilAppWindowIsFullyLoaded(appSurfaceId);
2821-
2822- verify(ApplicationManager.focusedApplicationId !== "unity8-dash")
2823-
2824- dashCommunicatorSpy.clear();
2825- // Minimize the application we just launched
2826- swipeFromLeftEdge(shell.width * 0.75);
2827-
2828- tryCompare(ApplicationManager, "focusedApplicationId", "unity8-dash");
2829-
2830- compare(dashCommunicatorSpy.count, 1);
2831- compare(dashCommunicatorSpy.signalArguments[0][0], 0);
2832- }
2833-
2834 function test_showInputMethod() {
2835 loadShell("phone");
2836 swipeAwayGreeter();
2837@@ -1166,7 +1027,7 @@
2838
2839 // Place the mouse against the window/screen edge and push beyond the barrier threshold
2840 mouseMove(shell, 0, shell.height / 2);
2841- launcher.pushEdge(EdgeBarrierSettings.pushThreshold * 1.1);
2842+ launcher.pushEdge(EdgeBarrierSettings.pushThreshold * .8);
2843
2844 var panel = findChild(launcher, "launcherPanel");
2845 verify(panel);
2846@@ -1186,9 +1047,7 @@
2847 waitUntilAppWindowIsFullyLoaded(appSurfaceId);
2848
2849 // Minimize the application we just launched
2850- swipeFromLeftEdge(shell.width * 0.75);
2851-
2852- waitUntilDashIsFocused();
2853+ swipeFromLeftEdge(units.gu(15));
2854
2855 showGreeter();
2856
2857
2858=== modified file 'tests/qmltests/tst_ShellWithPin.qml'
2859--- tests/qmltests/tst_ShellWithPin.qml 2016-09-22 10:33:39 +0000
2860+++ tests/qmltests/tst_ShellWithPin.qml 2016-12-07 18:01:28 +0000
2861@@ -547,71 +547,5 @@
2862 var lockscreen = findChild(shell, "lockscreen");
2863 verify(lockscreen.shown);
2864 }
2865-
2866- /*
2867- Regression test for https://bugs.launchpad.net/ubuntu/+source/unity8/+bug/1393447
2868-
2869- Do a left edge drag that is long enough to start displacing the greeter
2870- but short engough so that the greeter comes back into place once the
2871- finger is lifted.
2872-
2873- In this situation the launcher should remaing fully shown and hide itself
2874- only after its idle timeout is triggered.
2875- */
2876- function test_shortLeftEdgeSwipeMakesLauncherStayVisible() {
2877- showGreeter();
2878-
2879- var launcher = testCase.findChild(shell, "launcher")
2880- var launcherPanel = testCase.findChild(launcher, "launcherPanel");
2881-
2882- var toX = shell.width * 0.45;
2883- touchFlick(shell,
2884- 1 /* fromX */, shell.height * 0.5 /* fromY */,
2885- toX /* toX */, shell.height * 0.5 /* toY */,
2886- true /* beginTouch */, false /* endTouch */,
2887- 50, 100);
2888-
2889- // Launcher must be fully shown by now
2890- tryCompare(launcherPanel, "x", 0);
2891-
2892- // Greeter should be displaced
2893- var coverPage = findChild(shell, "coverPage");
2894- tryCompareFunction(function() { return coverPage.mapToItem(shell, 0, 0).x > shell.width*0.2; }, true);
2895-
2896- touchRelease(shell, toX, shell.height * 0.5);
2897-
2898- // Upon release the greeter should have slid back into full view
2899- tryCompareFunction(function() { return coverPage.mapToItem(shell, 0, 0).x === 0; }, true);
2900-
2901- // And the launcher should stay fully shown
2902- for (var i = 0; i < 10; ++i) {
2903- wait(50);
2904- compare(launcherPanel.x, 0);
2905- }
2906- }
2907-
2908- function test_longLeftEdgeDrags() {
2909- var coverPage = findChild(shell, "coverPage");
2910- var lockscreen = findChild(shell, "lockscreen");
2911- var launcher = findChild(shell, "launcherPanel");
2912- var galleryApp = ApplicationManager.startApplication("gallery-app");
2913- tryCompare(shell, "mainApp", galleryApp);
2914-
2915- // Show greeter
2916- showGreeter();
2917-
2918- // Swipe cover page away
2919- touchFlick(shell, 2, shell.height / 2, units.gu(30), shell.height / 2);
2920- tryCompare(launcher, "x", -launcher.width);
2921- tryCompare(coverPage, "showProgress", 0);
2922- compare(lockscreen.shown, true);
2923- tryCompare(shell, "mainApp", galleryApp);
2924-
2925- // Now attempt a swipe on lockscreen
2926- touchFlick(shell, 2, shell.height / 2, units.gu(30), shell.height / 2);
2927- tryCompare(launcher, "x", 0);
2928- compare(lockscreen.shown, true);
2929- tryCompare(shell, "mainApp", galleryApp);
2930- }
2931 }
2932 }

Subscribers

People subscribed via source and target branches