Merge lp:~nick-dedekind/unity8/expanded-panel-design into lp:unity8

Proposed by Nick Dedekind
Status: Merged
Approved by: Michael Terry
Approved revision: 1339
Merged at revision: 1376
Proposed branch: lp:~nick-dedekind/unity8/expanded-panel-design
Merge into: lp:unity8
Prerequisite: lp:~nick-dedekind/unity8/sharedunitymenumodel
Diff against target: 5736 lines (+2171/-2135)
56 files modified
plugins/Unity/Indicators/Indicators.qmltypes (+2/-4)
plugins/Unity/Indicators/indicators.h (+0/-2)
plugins/Unity/Indicators/indicatorsmodel.cpp (+0/-6)
plugins/Unity/Indicators/rootactionstate.cpp (+1/-1)
plugins/Unity/Indicators/rootactionstate.h (+4/-4)
plugins/Unity/Indicators/sharedunitymenumodel.cpp (+6/-1)
plugins/Unity/Indicators/unitymenumodelcache.cpp (+1/-5)
plugins/Unity/Indicators/unitymenumodelcache.h (+1/-3)
plugins/Unity/Indicators/visibleindicatorsmodel.cpp (+0/-2)
qml/Components/DragHandle.qml (+6/-1)
qml/Components/EdgeDemo.qml (+13/-10)
qml/Components/ListItems/VerticalThinDivider.qml (+0/-26)
qml/Components/ScrollCalculator.qml (+81/-0)
qml/Panel/Handle.qml (+43/-0)
qml/Panel/IndicatorItem.qml (+0/-53)
qml/Panel/IndicatorItemRow.qml (+297/-0)
qml/Panel/IndicatorPage.qml (+10/-16)
qml/Panel/IndicatorRow.qml (+0/-163)
qml/Panel/Indicators.qml (+0/-415)
qml/Panel/Indicators/DefaultIndicatorWidget.qml (+0/-119)
qml/Panel/Indicators/IndicatorBase.qml (+1/-5)
qml/Panel/Indicators/IndicatorDelegate.qml (+2/-2)
qml/Panel/Indicators/VisibleIndicators.qml (+4/-5)
qml/Panel/Indicators/client/IndicatorRepresentation.qml (+22/-11)
qml/Panel/Indicators/client/IndicatorsList.qml (+2/-2)
qml/Panel/Indicators/client/IndicatorsTree.qml (+4/-26)
qml/Panel/IndicatorsBar.qml (+269/-0)
qml/Panel/IndicatorsMenu.qml (+318/-0)
qml/Panel/MenuContent.qml (+26/-83)
qml/Panel/Panel.qml (+0/-191)
qml/Panel/PanelVelocityCalculator.qml (+54/-0)
qml/Shell.qml (+16/-5)
tests/autopilot/unity8/indicators/tests/test_indicators.py (+1/-1)
tests/autopilot/unity8/shell/emulators/main_window.py (+6/-6)
tests/mocks/Unity/Indicators/Indicators.qmltypes (+2/-4)
tests/mocks/Unity/Indicators/IndicatorsModel.qml (+89/-79)
tests/mocks/Unity/Indicators/RootActionState.qml (+2/-2)
tests/mocks/Unity/Indicators/fakeindicatorsmodel.cpp (+0/-2)
tests/mocks/Unity/Indicators/fakeunitymenumodelcache.cpp (+10/-8)
tests/mocks/Unity/Indicators/fakeunitymenumodelcache.h (+4/-8)
tests/qmltests/CMakeLists.txt (+5/-5)
tests/qmltests/Greeter/tst_Clock.qml (+1/-3)
tests/qmltests/Panel/IndicatorTest.qml (+80/-0)
tests/qmltests/Panel/Indicators/tst_DefaultIndicatorWidget.qml (+0/-52)
tests/qmltests/Panel/tst_ActiveCallHint.qml (+0/-1)
tests/qmltests/Panel/tst_IndicatorItem.qml (+0/-50)
tests/qmltests/Panel/tst_IndicatorItemRow.qml (+290/-0)
tests/qmltests/Panel/tst_IndicatorPage.qml (+5/-7)
tests/qmltests/Panel/tst_IndicatorRow.qml (+0/-158)
tests/qmltests/Panel/tst_Indicators.qml (+0/-231)
tests/qmltests/Panel/tst_IndicatorsBar.qml (+224/-0)
tests/qmltests/Panel/tst_IndicatorsMenu.qml (+258/-0)
tests/qmltests/Panel/tst_MenuContent.qml (+9/-17)
tests/qmltests/Panel/tst_Panel.qml (+0/-337)
tests/qmltests/Panel/tst_SearchIndicator.qml (+0/-1)
tests/qmltests/tst_Shell.qml (+2/-2)
To merge this branch: bzr merge lp:~nick-dedekind/unity8/expanded-panel-design
Reviewer Review Type Date Requested Status
Michael Terry Approve
PS Jenkins bot (community) continuous-integration Needs Fixing
Daniel d'Andrada (community) Abstain
MichaƂ Sawicz Needs Fixing
Albert Astals Cid (community) Abstain
Andrea Cimitan (community) Needs Fixing
Nick Dedekind (community) Needs Fixing
Omer Akram functional Pending
Review via email: mp+237031@code.launchpad.net

Commit message

Implementation of expandable panel design

Description of the change

New Panel design described in:
https://docs.google.com/a/canonical.com/document/d/1jHIGzAzf7kFELgOiU9J0Hd9mOa3NzTsnEglLmx_qEfk/edit#heading=h.lo6wjg7251og

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

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

 * Did you make sure that your branch does not contain spurious tags?
Yes

 * If you changed the packaging (debian), did you subscribe the ubuntu-unity team to this MP?
N/A

 * If you changed the UI, has there been a design review?
No

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Nick Dedekind (nick-dedekind) wrote :

From Vesa:

The invisible commit line shouldn't be there any more. User should be able to make the selection until finger is released regardless of vertical position. Also means the when closing indicators the selection should change immediately after the drag is started.

Combining icons is fine as it is. You asked about this on irc. We want icons to be combined even though it was not mentioned in the document. And multiple icons representing single menu is ok.

Velocity detection to prevent the item change is too aggressive? Makes the UI quite unresponsive when moving horizontally and making selection. The old indicators implementation suffered from the same issue.

Autoscroll is a bit jarring sometimes. Anyway to fix it?

Wobbly effect of the highlight when item changes. Could we get rid of that? I know my prototype has it and it most probably is due to the different timings of two different behavior that are then combined to create the full effect. But this is actually unwanted behavior. For example the current indicators implementation handles the highlight change smoothly which is what we want here as well.

Aligning items to left after release/commit. If you swipe down from transfers for example, after release it should scroll to align the left most item to left of the screen.

review: Needs Fixing
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Andrea Cimitan (cimi) wrote :

Ordering properties and signals for those files:

qml/Components/ScrollCalculator.qml
qml/Panel/IndicatorItemRow.qml

And coming...

review: Needs Fixing
Revision history for this message
Andrea Cimitan (cimi) wrote :

More

Revision history for this message
Nick Dedekind (nick-dedekind) wrote :

> More

Addressed all i think. Added a few comments to yours.

Revision history for this message
Nick Dedekind (nick-dedekind) wrote :

Comments for review

Revision history for this message
Andrea Cimitan (cimi) wrote :

Thanks for addressing... I still feel like we need more time to understand the logic and see if we can write it more simply, added a few comments, will ask another review! more eyes are better!

Revision history for this message
Andrea Cimitan (cimi) :
Revision history for this message
Andrea Cimitan (cimi) :
Revision history for this message
Andrea Cimitan (cimi) :
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Nick Dedekind (nick-dedekind) wrote :

more comments + fixes.

Revision history for this message
Albert Astals Cid (aacid) wrote :

Text conflict in qml/Shell.qml
Text conflict in tests/qmltests/CMakeLists.txt
Text conflict in tests/qmltests/tst_ShellWithPin.qml
3 conflicts encountered.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Albert Astals Cid (aacid) wrote :

$ bzr tags | grep ?
0.1.16 ?

review: Needs Fixing
Revision history for this message
Nick Dedekind (nick-dedekind) wrote :

> $ bzr tags | grep ?
> 0.1.16 ?

removed

Revision history for this message
Nick Dedekind (nick-dedekind) wrote :

> Thanks for addressing... I still feel like we need more time to understand the
> logic and see if we can write it more simply, added a few comments, will ask
> another review! more eyes are better!

I've addressed some of the complexity as well as fixed some of the bugs.

1316. By Nick Dedekind

reverted debug change

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Albert Astals Cid (aacid) wrote :
Revision history for this message
Daniel d'Andrada (dandrader) wrote :

In qml/Panel/PanelVelocityCalculator.qml:

It looks like every time the velocityTimer is triggered, the velocity is being calculated twice (stopLateralChanges being updated twice).

"""
2418 + calc.trackedPosition = trackedValue;
2419 + root.stopLateralChanges = Math.abs(calc.calculate()) > velocityThreashold;
"""

Line 2418 will trigger calc.onTrackedPositionChanged() which does the same as line 2419.

review: Needs Fixing
Revision history for this message
Albert Astals Cid (aacid) wrote :

So i did this:
 * Swipe down on the time & date indicator
 * Release finger from phone
 * Decide i want to see Network
 * Tap on the Network icon
 * Decide i want to close the indicators
 * Put finger horizontally in the middle of the bottom of the phone and swipe up
 * The indicator gets changed to battery

I find this behaviour weird, have you asked design?

Revision history for this message
Nick Dedekind (nick-dedekind) wrote :

> So i did this:
> * Swipe down on the time & date indicator
> * Release finger from phone
> * Decide i want to see Network
> * Tap on the Network icon
> * Decide i want to close the indicators
> * Put finger horizontally in the middle of the bottom of the phone and swipe
> up
> * The indicator gets changed to battery
>
> I find this behaviour weird, have you asked design?

There is no locking threshold anymore, as requested by design. Indicator changes as soon as we swipe from bottom.
See first comment from Vesa's review above.

Revision history for this message
Nick Dedekind (nick-dedekind) wrote :

> > So i did this:
> > * Swipe down on the time & date indicator
> > * Release finger from phone
> > * Decide i want to see Network
> > * Tap on the Network icon
> > * Decide i want to close the indicators
> > * Put finger horizontally in the middle of the bottom of the phone and
> swipe
> > up
> > * The indicator gets changed to battery
> >
> > I find this behaviour weird, have you asked design?
>
> There is no locking threshold anymore, as requested by design. Indicator
> changes as soon as we swipe from bottom.
> See first comment from Vesa's review above.

And yes. I find it weird as well...

Revision history for this message
Daniel d'Andrada (dandrader) wrote :

> In qml/Panel/PanelVelocityCalculator.qml:
>
> It looks like every time the velocityTimer is triggered, the velocity is being
> calculated twice (stopLateralChanges being updated twice).
>
> """
> 2418 + calc.trackedPosition = trackedValue;
> 2419 + root.stopLateralChanges = Math.abs(calc.calculate()) >
> velocityThreashold;
> """
>
> Line 2418 will trigger calc.onTrackedPositionChanged() which does the same as
> line 2419.

So the velocity is actually being calculated on every single value change, but with the timer I think you indended to do it only every 50 milliseconds, right (to avoid unnecessary cpu load)?

Revision history for this message
Daniel d'Andrada (dandrader) wrote :

"""
    property real velocityThreashold: 0.4
"""

Typo: s/Threashold/Threshold

review: Needs Fixing
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Nick Dedekind (nick-dedekind) wrote :

> In qml/Panel/PanelVelocityCalculator.qml:
>
> It looks like every time the velocityTimer is triggered, the velocity is being
> calculated twice (stopLateralChanges being updated twice).
>
> """
> 2418 + calc.trackedPosition = trackedValue;
> 2419 + root.stopLateralChanges = Math.abs(calc.calculate()) >
> velocityThreashold;
> """
>
> Line 2418 will trigger calc.onTrackedPositionChanged() which does the same as
> line 2419.

Yes, but it's required since we need to do the calculation even if onTrackedPositionChanged doesnt change (for decrease in velocity). I've put in a check a guard only to do the recalc in the timer if the trackedPosition doesn't change.

1317. By Nick Dedekind

recalc guard

Revision history for this message
Nick Dedekind (nick-dedekind) wrote :

> """
> property real velocityThreashold: 0.4
> """
>
> Typo: s/Threashold/Threshold

Fixed.

1318. By Nick Dedekind

s/Threashold/Threshold

Revision history for this message
Daniel d'Andrada (dandrader) wrote :

> > In qml/Panel/PanelVelocityCalculator.qml:
> >
> > It looks like every time the velocityTimer is triggered, the velocity is
> being
> > calculated twice (stopLateralChanges being updated twice).
> >
> > """
> > 2418 + calc.trackedPosition = trackedValue;
> > 2419 + root.stopLateralChanges = Math.abs(calc.calculate()) >
> > velocityThreashold;
> > """
> >
> > Line 2418 will trigger calc.onTrackedPositionChanged() which does the same
> as
> > line 2419.
>
> Yes, but it's required since we need to do the calculation even if
> onTrackedPositionChanged doesnt change (for decrease in velocity). I've put in
> a check a guard only to do the recalc in the timer if the trackedPosition
> doesn't change.

Ahhh... now I got it, might make sense then to stick to updating the velocity every 50ms, ie only on the timer, instead of both due to timer timeout and due to tracked value change, to be consistent. Will hopefully simplify the code as well.

Also it seems this timer is always running. You don't seem to ever stop it?

Revision history for this message
Daniel d'Andrada (dandrader) wrote :

> Ahhh... now I got it, might make sense then to stick to updating the velocity
> every 50ms, ie only on the timer, instead of both due to timer timeout and due
> to tracked value change, to be consistent. Will hopefully simplify the code as
> well.
>
> Also it seems this timer is always running. You don't seem to ever stop it?

Nevermind that. Timer.repeat defaults to false. :)

1319. By Nick Dedekind

performance tweaks.

Revision history for this message
Nick Dedekind (nick-dedekind) wrote :

> > > In qml/Panel/PanelVelocityCalculator.qml:
> > >
> > > It looks like every time the velocityTimer is triggered, the velocity is
> > being
> > > calculated twice (stopLateralChanges being updated twice).
> > >
> > > """
> > > 2418 + calc.trackedPosition = trackedValue;
> > > 2419 + root.stopLateralChanges = Math.abs(calc.calculate()) >
> > > velocityThreashold;
> > > """
> > >
> > > Line 2418 will trigger calc.onTrackedPositionChanged() which does the same
> > as
> > > line 2419.
> >
> > Yes, but it's required since we need to do the calculation even if
> > onTrackedPositionChanged doesnt change (for decrease in velocity). I've put
> in
> > a check a guard only to do the recalc in the timer if the trackedPosition
> > doesn't change.
>
> Ahhh... now I got it, might make sense then to stick to updating the velocity
> every 50ms, ie only on the timer, instead of both due to timer timeout and due
> to tracked value change, to be consistent. Will hopefully simplify the code as
> well.

Ok, I've moved everything into a update function.
I've also improved performance by only starting the timer if tracked, and only emitting the threshold signal if it was previously in "stopped mode".

>
> Also it seems this timer is always running. You don't seem to ever stop it?

1320. By Nick Dedekind

even better velocity calc

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Daniel d'Andrada (dandrader) wrote :

"""
                enableLateralChanges: {
                    if (!d.activeDragHandle) return false;
                    if (!d.activeDragHandle.dragging) return false;

                    return !yVelocityCalculator.stopLateralChanges;
                }
"""

Could be simply:

                enableLateralChanges: d.activeDragHandle && d.activeDragHandle.dragging
                                   && !yVelocityCalculator.stopLateralChanges;

------------------------

PanelVelocityCalculator.stopLateralChanges is breaking encapsulation. PanelVelocityCalculator doesn't know anything about lateral changes. IndicatorsMenu do. All PanelVelocityCalculator knows is whether the trackedValue velocity is above or below the given threshold.

Thus:

bar.enableLateralChanges: d.activeDragHandle && d.activeDragHandle.dragging
                                   && !yVelocityCalculator.velocityAboveThreshold

In IndicatorsMenu.qml

"""
        onVelocityThresholdTriggered: bar.updateItemFromLateralPosition(bar.lateralPosition);
"""

There should be no need for this code, and thus, for this velocityThresholdTriggered signal.
IndicatorItemRow should be smart enough to call that function himself once his enableLateralChanges property gets changed to true.

review: Needs Fixing
Revision history for this message
Daniel d'Andrada (dandrader) wrote :

> """
> onVelocityThresholdTriggered:
> bar.updateItemFromLateralPosition(bar.lateralPosition);
> """
>
>
> There should be no need for this code, and thus, for this
> velocityThresholdTriggered signal.
> IndicatorItemRow should be smart enough to call that function himself once his
> enableLateralChanges property gets changed to true.

Then this function in IndicatorsBar.qml could go away as well:

"""
    function updateItemFromLateralPosition(position) {
        if (position === -1) return;

        var mapped = root.mapToItem(row, position, 0);
        row.updateItemFromLateralPosition(mapped.x);
    }
"""

Revision history for this message
Daniel d'Andrada (dandrader) wrote :

In Panel.qml:

"""
VerticalThinDivider {
    id: indicatorDividor
    anchors {
        top: indicators.top
        bottom: indicators.bottom
        right: indicators.left

        topMargin: indicatorArea.anchors.topMargin + indicators.minimizedPanelHeight
    }

    width: units.dp(2)
    source: "graphics/VerticalDivider.png"
}
"""

Should we still be using the VerticalThinDivider component for that? By looking at VerticalThinDivider.qml, I see that you're overwriting everything it does. So it would be better to use an Image there directly. We could then remove VerticalThinDivider.qml file and the ListItemDividerVertical.png file it uses, this is is the sole user of that component.

Could also get rid of the "id:" line as it's currently not used and has a typo anyway.

review: Needs Fixing
1321. By Nick Dedekind

review comments

1322. By Nick Dedekind

AP emulator update

Revision history for this message
Nick Dedekind (nick-dedekind) wrote :

> """
> enableLateralChanges: {
> if (!d.activeDragHandle) return false;
> if (!d.activeDragHandle.dragging) return false;
>
> return !yVelocityCalculator.stopLateralChanges;
> }
> """
>
> Could be simply:
>
> enableLateralChanges: d.activeDragHandle &&
> d.activeDragHandle.dragging
> && !yVelocityCalculator.stopLateralChanges;
>
> ------------------------
>
> PanelVelocityCalculator.stopLateralChanges is breaking encapsulation.
> PanelVelocityCalculator doesn't know anything about lateral changes.
> IndicatorsMenu do. All PanelVelocityCalculator knows is whether the
> trackedValue velocity is above or below the given threshold.
>
> Thus:
>
> bar.enableLateralChanges: d.activeDragHandle && d.activeDragHandle.dragging
> &&
> !yVelocityCalculator.velocityAboveThreshold
>
>
> In IndicatorsMenu.qml
>
> """
> onVelocityThresholdTriggered:
> bar.updateItemFromLateralPosition(bar.lateralPosition);
> """
>
>
> There should be no need for this code, and thus, for this
> velocityThresholdTriggered signal.
> IndicatorItemRow should be smart enough to call that function himself once his
> enableLateralChanges property gets changed to true.

Fixed all + other reviews.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Timo Jyrinki (timo-jyrinki) wrote :

This should be targeted to the rtm-14.09 branch, or alternatively there should be a duplicate of this branch targeting it, so that it can be included in the silo.

Revision history for this message
MichaƂ Sawicz (saviq) wrote :

> This should be targeted to the rtm-14.09 branch, or alternatively there should
> be a duplicate of this branch targeting it, so that it can be included in the
> silo.

Yup, already there:
https://code.launchpad.net/~nick-dedekind/unity8/expanded-panel-design

Revision history for this message
Albert Astals Cid (aacid) wrote :

Text conflict in qml/Panel/IndicatorPage.qml
Contents conflict in qml/Panel/IndicatorRow.qml
Text conflict in qml/Panel/Indicators/client/IndicatorsTree.qml
Text conflict in qml/Panel/MenuContent.qml
Text conflict in tests/qmltests/tst_ShellWithPin.qml
5 conflicts encountered.

review: Needs Fixing
1323. By Nick Dedekind

merged with trunk

1324. By Nick Dedekind

fixed include

Revision history for this message
Nick Dedekind (nick-dedekind) wrote :

> Text conflict in qml/Panel/IndicatorPage.qml
> Contents conflict in qml/Panel/IndicatorRow.qml
> Text conflict in qml/Panel/Indicators/client/IndicatorsTree.qml
> Text conflict in qml/Panel/MenuContent.qml
> Text conflict in tests/qmltests/tst_ShellWithPin.qml
> 5 conflicts encountered.

Fixed

1325. By Nick Dedekind

sync indicator page delegate loader

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Daniel d'Andrada (dandrader) wrote :

I don't see the use for that previouslyStopped var in qml/Panel/PanelVelocityCalculator.qml

Couldn't it just be like this?
http://paste.ubuntu.com/8558834/

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Andrea Cimitan (cimi) wrote :

> I don't see the use for that previouslyStopped var in
> qml/Panel/PanelVelocityCalculator.qml
>
> Couldn't it just be like this?
> http://paste.ubuntu.com/8558834/
if velocityAboveThreshold is false before calling update then turns true during it, then your patch won't work..

Revision history for this message
Albert Astals Cid (aacid) wrote :

Others seem to be taking good care of this and on my previous quick reads/tests of the code i could not find anything glaringly wrong, so abstaining

review: Abstain
1326. By Nick Dedekind

remove previouslyStopped

Revision history for this message
Nick Dedekind (nick-dedekind) wrote :

> I don't see the use for that previouslyStopped var in
> qml/Panel/PanelVelocityCalculator.qml
>
> Couldn't it just be like this?
> http://paste.ubuntu.com/8558834/

old code from when we were using a signal.
removed.

Revision history for this message
Nick Dedekind (nick-dedekind) wrote :

> > I don't see the use for that previouslyStopped var in
> > qml/Panel/PanelVelocityCalculator.qml
> >
> > Couldn't it just be like this?
> > http://paste.ubuntu.com/8558834/
> if velocityAboveThreshold is false before calling update then turns true
> during it, then your patch won't work..

It will. the timer gets started if velocityAboveThreshold is set to true. Code was old from when there was a signal that i didn't want emitted all the time.

Revision history for this message
MichaƂ Sawicz (saviq) wrote :

There's a problem with the SIM unlock notification:
https://docs.google.com/a/canonical.com/file/d/0B32jwBcbaPloQW9BNXBhUFpHX1k/edit

Also, the white highlight "lags" behind the indicator in expanded state, try turning the flight mode on/off.

review: Needs Fixing
1327. By Nick Dedekind

full screen notifications don't include panel

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Daniel d'Andrada (dandrader) wrote :

ScrollCalculator looks pretty specific to the indicators panel problem.
So I think it would be better to have it in qml/Panel dir than in qml/Components.

Revision history for this message
Daniel d'Andrada (dandrader) wrote :

Didn't take the time properly understand all the code but didn't find anything else that looked wrong.
Glad to see that we have tests for all those Panel subcomponents.

review: Abstain
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
1328. By Nick Dedekind

remove/add item fixes

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
1329. By Nick Dedekind

fixed edge demo

1330. By Nick Dedekind

Expanded visible indicators.

1331. By Nick Dedekind

fixed root action state visible

Revision history for this message
Nick Dedekind (nick-dedekind) wrote :

I've updated this so that indicators marked as "non-visible" show up when you expand the indicator.
Also fixed the edge demo.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
1332. By Nick Dedekind

isIndicatorVisible->indicatorVisible

1333. By Nick Dedekind

merge with sharedunitymenumodel branch

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
1334. By Nick Dedekind

more efficient delegate draws

Revision history for this message
Michael Terry (mterry) wrote :

Two bugs seen that I'm trying to be able to reproduce:

- Once, the battery and datetime indicators had no menucontent. We confirmed that the services were running and exporting their menus though.

- Once, I got a u8 crash when playing with flight mode and the menu indicator. When it crashed, there were three icons for the network indicator, when usually there are at most two. I don't remember which three.

Working on finding out if these are branch specific or what.

Revision history for this message
Michael Terry (mterry) wrote :

The crash can be reproduced by simply toggling Flight Mode a bunch. The three icons I saw were the airplane, SIM card, and Wi-Fi. Those three can be seen to appear briefly sometimes when enabling Flight Mode (the SIM card immediately disappears down to two icons though). But in this crash, it seems we crash before the SIM card icon disappears.

Here's the stacktrace for the crash: http://paste.ubuntu.com/8605407/

1335. By Nick Dedekind

fixed indicator realignment

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
1336. By Nick Dedekind

re-add commit line for redrag

Revision history for this message
Michael Terry (mterry) wrote :

OK, was able to reproduce an almost identical crash with the utopic debs. So not a new crash with this image.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
1337. By Nick Dedekind

better indicator switch detection

1338. By Nick Dedekind

more required to shed lock

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
1339. By Nick Dedekind

fix async object creation missing unitymenumodel signal

Revision history for this message
Michael Terry (mterry) wrote :

OK looks good enough! Let's get 'er done.

 * 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.
 No, for usual reasons.

 * Did you make sure that the branch does not contain spurious tags?
 Yes

review: Approve
1340. By Nick Dedekind

removed StopAtBounds

Revision history for this message
Michael Terry (mterry) wrote :

Nick wanted me to re-approve after his change. Still looks fine.

Revision history for this message
Michael Terry (mterry) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'plugins/Unity/Indicators/Indicators.qmltypes'
2--- plugins/Unity/Indicators/Indicators.qmltypes 2014-10-21 21:16:04 +0000
3+++ plugins/Unity/Indicators/Indicators.qmltypes 2014-10-21 21:16:05 +0000
4@@ -99,10 +99,8 @@
5 values: {
6 "Identifier": 0,
7 "Position": 1,
8- "WidgetSource": 2,
9- "PageSource": 3,
10- "IndicatorProperties": 4,
11- "IsVisible": 5
12+ "IndicatorProperties": 2,
13+ "IsVisible": 3
14 }
15 }
16 }
17
18=== modified file 'plugins/Unity/Indicators/indicators.h'
19--- plugins/Unity/Indicators/indicators.h 2013-09-17 12:31:19 +0000
20+++ plugins/Unity/Indicators/indicators.h 2014-10-21 21:16:05 +0000
21@@ -74,8 +74,6 @@
22 enum Roles {
23 Identifier = 0,
24 Position,
25- WidgetSource,
26- PageSource,
27 IndicatorProperties,
28 IsVisible
29 };
30
31=== modified file 'plugins/Unity/Indicators/indicatorsmodel.cpp'
32--- plugins/Unity/Indicators/indicatorsmodel.cpp 2014-01-30 14:54:01 +0000
33+++ plugins/Unity/Indicators/indicatorsmodel.cpp 2014-10-21 21:16:05 +0000
34@@ -202,8 +202,6 @@
35 {
36 roles[IndicatorsModelRole::Identifier] = "identifier";
37 roles[IndicatorsModelRole::Position] = "position";
38- roles[IndicatorsModelRole::WidgetSource] = "widgetSource";
39- roles[IndicatorsModelRole::PageSource] = "pageSource";
40 roles[IndicatorsModelRole::IndicatorProperties] = "indicatorProperties";
41 }
42 return roles;
43@@ -248,10 +246,6 @@
44 return QVariant(indicator->indicatorProperties());
45 }
46 break;
47- case IndicatorsModelRole::WidgetSource:
48- return qmlDirectory()+"/Panel/Indicators/DefaultIndicatorWidget.qml";
49- case IndicatorsModelRole::PageSource:
50- return qmlDirectory()+"/Panel/Indicators/DefaultIndicatorPage.qml";
51 default:
52 break;
53 }
54
55=== modified file 'plugins/Unity/Indicators/rootactionstate.cpp'
56--- plugins/Unity/Indicators/rootactionstate.cpp 2014-08-26 08:14:44 +0000
57+++ plugins/Unity/Indicators/rootactionstate.cpp 2014-10-21 21:16:05 +0000
58@@ -156,7 +156,7 @@
59 return m_cachedState.value("accessible-desc", QVariant::fromValue(QString())).toString();
60 }
61
62-bool RootActionState::isVisible() const
63+bool RootActionState::indicatorVisible() const
64 {
65 if (!isValid()) return false;
66
67
68=== modified file 'plugins/Unity/Indicators/rootactionstate.h'
69--- plugins/Unity/Indicators/rootactionstate.h 2013-10-11 14:32:29 +0000
70+++ plugins/Unity/Indicators/rootactionstate.h 2014-10-21 21:16:05 +0000
71@@ -37,7 +37,7 @@
72 Q_PROPERTY(QString rightLabel READ rightLabel NOTIFY rightLabelChanged)
73 Q_PROPERTY(QStringList icons READ icons NOTIFY iconsChanged)
74 Q_PROPERTY(QString accessibleName READ accessibleName NOTIFY accessibleNameChanged)
75- Q_PROPERTY(bool visible READ isVisible NOTIFY visibleChanged)
76+ Q_PROPERTY(bool indicatorVisible READ indicatorVisible NOTIFY indicatorVisibleChanged)
77 public:
78 RootActionState(QObject *parent = 0);
79 virtual ~RootActionState();
80@@ -54,10 +54,10 @@
81 QString rightLabel() const;
82 QStringList icons() const;
83 QString accessibleName() const;
84- bool isVisible() const;
85+ bool indicatorVisible() const;
86
87 // from ActionStateParser
88- virtual QVariant toQVariant(GVariant* state) const;
89+ virtual QVariant toQVariant(GVariant* state) const override;
90
91 Q_SIGNALS:
92 void updated();
93@@ -71,7 +71,7 @@
94 void rightLabelChanged();
95 void iconsChanged();
96 void accessibleNameChanged();
97- void visibleChanged();
98+ void indicatorVisibleChanged();
99
100 private Q_SLOTS:
101 void onModelRowsAdded(const QModelIndex& parent, int start, int end);
102
103=== modified file 'plugins/Unity/Indicators/sharedunitymenumodel.cpp'
104--- plugins/Unity/Indicators/sharedunitymenumodel.cpp 2014-10-21 21:16:04 +0000
105+++ plugins/Unity/Indicators/sharedunitymenumodel.cpp 2014-10-21 21:16:05 +0000
106@@ -18,6 +18,8 @@
107 #include "sharedunitymenumodel.h"
108 #include "unitymenumodelcache.h"
109
110+#include <unitymenumodel.h>
111+
112 SharedUnityMenuModel::SharedUnityMenuModel(QObject* parent)
113 : QObject(parent)
114 {
115@@ -78,8 +80,11 @@
116 Q_EMIT modelChanged();
117 }
118 } else {
119- QSharedPointer<UnityMenuModel> model = UnityMenuModelCache::singleton()->model(m_busName, m_menuObjectPath, m_actions);
120+ QSharedPointer<UnityMenuModel> model = UnityMenuModelCache::singleton()->model(m_menuObjectPath);
121 if (model != m_model) {
122+ if (model->busName() != m_busName) model->setBusName(m_busName);
123+ if (model->actions() != m_actions) model->setActions(m_actions);
124+
125 m_model = model;
126 Q_EMIT modelChanged();
127 }
128
129=== modified file 'plugins/Unity/Indicators/unitymenumodelcache.cpp'
130--- plugins/Unity/Indicators/unitymenumodelcache.cpp 2014-10-21 21:16:04 +0000
131+++ plugins/Unity/Indicators/unitymenumodelcache.cpp 2014-10-21 21:16:05 +0000
132@@ -37,9 +37,7 @@
133 {
134 }
135
136-QSharedPointer<UnityMenuModel> UnityMenuModelCache::model(const QByteArray& bus,
137- const QByteArray& path,
138- const QVariantMap& actions)
139+QSharedPointer<UnityMenuModel> UnityMenuModelCache::model(const QByteArray& path)
140 {
141 if (m_registry.contains(path))
142 return m_registry[path];
143@@ -60,9 +58,7 @@
144 });
145 m_registry[path] = menuModel.toWeakRef();
146
147- menuModel->setBusName(bus);
148 menuModel->setMenuObjectPath(path);
149- menuModel->setActions(actions);
150 return menuModel;
151 }
152
153
154=== modified file 'plugins/Unity/Indicators/unitymenumodelcache.h'
155--- plugins/Unity/Indicators/unitymenumodelcache.h 2014-10-21 21:16:04 +0000
156+++ plugins/Unity/Indicators/unitymenumodelcache.h 2014-10-21 21:16:05 +0000
157@@ -37,9 +37,7 @@
158
159 static UnityMenuModelCache* singleton();
160
161- virtual QSharedPointer<UnityMenuModel> model(const QByteArray& bus,
162- const QByteArray& path,
163- const QVariantMap& actions);
164+ virtual QSharedPointer<UnityMenuModel> model(const QByteArray& path);
165
166 // for tests use
167 Q_INVOKABLE virtual bool contains(const QByteArray& path);
168
169=== modified file 'plugins/Unity/Indicators/visibleindicatorsmodel.cpp'
170--- plugins/Unity/Indicators/visibleindicatorsmodel.cpp 2013-09-17 12:31:19 +0000
171+++ plugins/Unity/Indicators/visibleindicatorsmodel.cpp 2014-10-21 21:16:05 +0000
172@@ -33,8 +33,6 @@
173 {
174 roles[IndicatorsModelRole::Identifier] = "identifier";
175 roles[IndicatorsModelRole::Position] = "position";
176- roles[IndicatorsModelRole::WidgetSource] = "widgetSource";
177- roles[IndicatorsModelRole::PageSource] = "pageSource";
178 roles[IndicatorsModelRole::IndicatorProperties] = "indicatorProperties";
179 roles[IndicatorsModelRole::IsVisible] = "isVisible";
180 }
181
182=== modified file 'qml/Components/DragHandle.qml'
183--- qml/Components/DragHandle.qml 2014-10-01 13:20:32 +0000
184+++ qml/Components/DragHandle.qml 2014-10-21 21:16:05 +0000
185@@ -68,6 +68,7 @@
186 }
187
188 property real hintDisplacement: 0
189+ property var overrideStartValue: undefined
190 SmoothedAnimation {
191 id: hintingAnimation
192 target: hintingAnimation
193@@ -196,7 +197,11 @@
194 } else /* Undecided || Recognized */ {
195 if (d.previousStatus === DirectionalDragArea.WaitingForTouch) {
196 dragEvaluator.reset();
197- d.startValue = parent[d.targetProp];
198+ if (overrideStartValue !== undefined) {
199+ d.startValue = overrideStartValue;
200+ } else {
201+ d.startValue = parent[d.targetProp];
202+ }
203
204 if (hintDisplacement > 0) {
205 hintingAnimation.targetValue = d.startValue;
206
207=== modified file 'qml/Components/EdgeDemo.qml'
208--- qml/Components/EdgeDemo.qml 2014-08-06 14:33:50 +0000
209+++ qml/Components/EdgeDemo.qml 2014-10-21 21:16:05 +0000
210@@ -23,7 +23,7 @@
211
212 property Item greeter
213 property Item launcher
214- property Item indicators
215+ property Item panel
216 property Item stages
217
218 property bool launcherEnabled: true
219@@ -139,11 +139,11 @@
220 function startTopEdgeDemo() {
221 demo.panelEnabled = true;
222 if (demo.stages) {
223- d.topEdgeDemo = d.overlay.createObject(demo.stages, {
224+ d.topEdgeDemo = d.overlay.createObject(demo.panel, {
225 "edge": "top",
226 "title": i18n.tr("Top edge"),
227 "text": i18n.tr("Try swiping from the top edge to access the indicators"),
228- "anchors.fill": demo.stages,
229+ "anchors.fill": demo.panel,
230 });
231 }
232 if (d.topEdgeDemo) {
233@@ -154,9 +154,9 @@
234 }
235
236 Connections {
237- target: demo.indicators
238+ target: demo.panel.indicators
239 onFullyOpenedChanged: {
240- if (d.topEdgeDemo && d.topEdgeDemo.available && demo.indicators.fullyOpened) {
241+ if (d.topEdgeDemo && d.topEdgeDemo.available && demo.panel.indicators.fullyOpened) {
242 d.topEdgeDemo.hideNow()
243 startBottomEdgeDemo()
244 }
245@@ -164,12 +164,12 @@
246 }
247
248 function startBottomEdgeDemo() {
249- if (demo.indicators) {
250- d.bottomEdgeDemo = d.overlay.createObject(demo.indicators, {
251+ if (demo.panel.indicators) {
252+ d.bottomEdgeDemo = d.overlay.createObject(demo.panel.indicators, {
253 "edge": "bottom",
254 "title": i18n.tr("Close"),
255 "text": i18n.tr("Swipe up again to close the settings screen"),
256- "anchors.fill": demo.indicators.content,
257+ "anchors.fill": demo.panel.indicators,
258 });
259 }
260 if (d.bottomEdgeDemo) {
261@@ -180,9 +180,12 @@
262 }
263
264 Connections {
265- target: demo.indicators
266+ target: demo.panel.indicators
267 onPartiallyOpenedChanged: {
268- if (d.bottomEdgeDemo && d.bottomEdgeDemo.available && !demo.indicators.partiallyOpened && !demo.indicators.fullyOpened) {
269+ if (d.bottomEdgeDemo &&
270+ d.bottomEdgeDemo.available &&
271+ !demo.panel.indicators.partiallyOpened &&
272+ !demo.panel.indicators.fullyOpened) {
273 d.bottomEdgeDemo.hideNow()
274 startLeftEdgeDemo()
275 }
276
277=== removed file 'qml/Components/ListItems/VerticalThinDivider.qml'
278--- qml/Components/ListItems/VerticalThinDivider.qml 2013-06-05 22:03:08 +0000
279+++ qml/Components/ListItems/VerticalThinDivider.qml 1970-01-01 00:00:00 +0000
280@@ -1,26 +0,0 @@
281-/*
282- * Copyright (C) 2012 Canonical, Ltd.
283- *
284- * This program is free software; you can redistribute it and/or modify
285- * it under the terms of the GNU General Public License as published by
286- * the Free Software Foundation; version 3.
287- *
288- * This program is distributed in the hope that it will be useful,
289- * but WITHOUT ANY WARRANTY; without even the implied warranty of
290- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
291- * GNU General Public License for more details.
292- *
293- * You should have received a copy of the GNU General Public License
294- * along with this program. If not, see <http://www.gnu.org/licenses/>.
295- */
296-
297-import QtQuick 2.0
298-
299-Image {
300- anchors {
301- top: (parent) ? parent.top : null
302- bottom: (parent) ? parent.bottom : null
303- }
304- width: (visible) ? units.dp(2) : 0
305- source: "graphics/ListItemDividerVertical.png"
306-}
307
308=== removed file 'qml/Components/ListItems/graphics/ListItemDividerVertical@18.png'
309Binary files qml/Components/ListItems/graphics/ListItemDividerVertical@18.png 2013-06-05 22:03:08 +0000 and qml/Components/ListItems/graphics/ListItemDividerVertical@18.png 1970-01-01 00:00:00 +0000 differ
310=== added file 'qml/Components/ScrollCalculator.qml'
311--- qml/Components/ScrollCalculator.qml 1970-01-01 00:00:00 +0000
312+++ qml/Components/ScrollCalculator.qml 2014-10-21 21:16:05 +0000
313@@ -0,0 +1,81 @@
314+/*
315+ * Copyright (C) 2014 Canonical, Ltd.
316+ *
317+ * This program is free software; you can redistribute it and/or modify
318+ * it under the terms of the GNU General Public License as published by
319+ * the Free Software Foundation; version 3.
320+ *
321+ * This program is distributed in the hope that it will be useful,
322+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
323+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
324+ * GNU General Public License for more details.
325+ *
326+ * You should have received a copy of the GNU General Public License
327+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
328+ */
329+
330+import QtQuick 2.2
331+import Ubuntu.Components 1.1
332+
333+Item {
334+ id: scrollArea
335+
336+ readonly property bool areaActive: lateralPosition >= 0
337+ property real stopScrollThreshold: units.gu(2)
338+ property int direction: Qt.LeftToRight
339+ property real baseScrollAmount: units.dp(3)
340+ property real maximumScrollAmount: units.dp(8)
341+ property real lateralPosition: -1
342+ property real forceScrollingPercentage: 0.4
343+
344+ signal scroll(real scrollAmount)
345+
346+ width: units.gu(5)
347+ rotation: direction === Qt.LeftToRight ? 0 : 180
348+
349+ onAreaActiveChanged: areaActive ? handleEnter() : handleExit()
350+
351+ function handleEnter() {
352+ d.thresholdAreaX = -scrollArea.stopScrollThreshold;
353+ scrollTimer.restart();
354+ }
355+
356+ function handleExit() {
357+ d.thresholdAreaX = -scrollArea.stopScrollThreshold;
358+ scrollTimer.stop();
359+ }
360+
361+ onLateralPositionChanged: {
362+ if (scrollArea.areaActive) {
363+ if (lateralPosition > width * (1 - forceScrollingPercentage)) {
364+ d.thresholdAreaX = width * (1 - forceScrollingPercentage);
365+ if (!scrollTimer.running) scrollTimer.restart();
366+ } else if (lateralPosition > d.thresholdAreaX + scrollArea.stopScrollThreshold) {
367+ d.thresholdAreaX = lateralPosition - scrollArea.stopScrollThreshold;
368+ if (!scrollTimer.running) scrollTimer.restart();
369+ } else if (lateralPosition < d.thresholdAreaX) {
370+ d.thresholdAreaX = lateralPosition;
371+ scrollTimer.stop();
372+ }
373+
374+ d.progression = lateralPosition / width;
375+ }
376+ }
377+
378+ Timer {
379+ id: scrollTimer
380+ interval: 16
381+ repeat: true
382+
383+ onTriggered: {
384+ var scrollAmount = scrollArea.baseScrollAmount + scrollArea.maximumScrollAmount * d.progression;
385+ scrollArea.scroll(scrollAmount);
386+ }
387+ }
388+
389+ QtObject {
390+ id: d
391+ property real progression: 0
392+ property real thresholdAreaX: -scrollArea.stopScrollThreshold
393+ }
394+}
395
396=== added file 'qml/Panel/Handle.qml'
397--- qml/Panel/Handle.qml 1970-01-01 00:00:00 +0000
398+++ qml/Panel/Handle.qml 2014-10-21 21:16:05 +0000
399@@ -0,0 +1,43 @@
400+/*
401+ * Copyright (C) 2014 Canonical, Ltd.
402+ *
403+ * This program is free software; you can redistribute it and/or modify
404+ * it under the terms of the GNU General Public License as published by
405+ * the Free Software Foundation; version 3.
406+ *
407+ * This program is distributed in the hope that it will be useful,
408+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
409+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
410+ * GNU General Public License for more details.
411+ *
412+ * You should have received a copy of the GNU General Public License
413+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
414+ */
415+
416+import QtQuick 2.2
417+import Ubuntu.Components 1.1
418+
419+Rectangle {
420+ id: handle
421+ color: "#333333"
422+ height: units.gu(2)
423+ property bool active: false
424+
425+ Row {
426+ id: dots
427+ width: childrenRect.width
428+ height: childrenRect.height
429+ anchors.centerIn: parent
430+ spacing: units.gu(0.5)
431+ Repeater {
432+ model: 3
433+ delegate: Rectangle {
434+ id: dot
435+ width: units.dp(3)
436+ height: width
437+ color: handle.active ? "#de4814" : "#717171"
438+ radius: units.dp(1)
439+ }
440+ }
441+ }
442+}
443
444=== removed file 'qml/Panel/IndicatorItem.qml'
445--- qml/Panel/IndicatorItem.qml 2014-09-29 10:24:58 +0000
446+++ qml/Panel/IndicatorItem.qml 1970-01-01 00:00:00 +0000
447@@ -1,53 +0,0 @@
448-/*
449- * Copyright (C) 2013 Canonical, Ltd.
450- *
451- * This program is free software; you can redistribute it and/or modify
452- * it under the terms of the GNU General Public License as published by
453- * the Free Software Foundation; version 3.
454- *
455- * This program is distributed in the hope that it will be useful,
456- * but WITHOUT ANY WARRANTY; without even the implied warranty of
457- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
458- * GNU General Public License for more details.
459- *
460- * You should have received a copy of the GNU General Public License
461- * along with this program. If not, see <http://www.gnu.org/licenses/>.
462- */
463-
464-import QtQuick 2.0
465-import Ubuntu.Components 0.1
466-import Unity.Indicators 0.1 as Indicators
467-import "../Components"
468-
469-Loader {
470- id: root
471-
472- property alias widgetSource: root.source
473- property bool dimmed: false
474- property var indicatorProperties: undefined
475- property bool indicatorVisible: item ? item.enabled : false
476- property string identifier
477-
478- opacity: dimmed ? 0.4 : 1
479- Behavior on opacity { UbuntuNumberAnimation { duration: UbuntuAnimation.BriskDuration } }
480-
481- onLoaded: {
482- for(var pName in indicatorProperties) {
483- if (item.hasOwnProperty(pName)) {
484- item[pName] = indicatorProperties[pName];
485- }
486- }
487- }
488-
489- Binding {
490- target: item
491- property: "identifier"
492- value: identifier
493- }
494-
495- Binding {
496- target: item
497- property: "objectName"
498- value: identifier + "-widget"
499- }
500-}
501
502=== added file 'qml/Panel/IndicatorItemRow.qml'
503--- qml/Panel/IndicatorItemRow.qml 1970-01-01 00:00:00 +0000
504+++ qml/Panel/IndicatorItemRow.qml 2014-10-21 21:16:05 +0000
505@@ -0,0 +1,297 @@
506+/*
507+ * Copyright (C) 2013-2014 Canonical, Ltd.
508+ *
509+ * This program is free software; you can redistribute it and/or modify
510+ * it under the terms of the GNU General Public License as published by
511+ * the Free Software Foundation; version 3.
512+ *
513+ * This program is distributed in the hope that it will be useful,
514+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
515+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
516+ * GNU General Public License for more details.
517+ *
518+ * You should have received a copy of the GNU General Public License
519+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
520+ */
521+
522+import QtQuick 2.2
523+import Ubuntu.Components 1.1
524+
525+Item {
526+ id: root
527+ width: row.width
528+ height: units.gu(3)
529+
530+ property QtObject indicatorsModel: null
531+ property real overFlowWidth: width
532+ property bool expanded: false
533+ property var currentItem
534+ readonly property int currentItemIndex: currentItem ? currentItem.ownIndex : -1
535+
536+ property real unitProgress: 0.0
537+ property real selectionChangeBuffer: units.gu(2)
538+ property bool enableLateralChanges: false
539+ property color hightlightColor: "#ededed"
540+
541+ property real lateralPosition: -1
542+ onLateralPositionChanged: {
543+ updateItemFromLateralPosition();
544+ }
545+
546+ onEnableLateralChangesChanged: {
547+ updateItemFromLateralPosition();
548+ }
549+
550+ function updateItemFromLateralPosition() {
551+ if (currentItem && !enableLateralChanges) return;
552+ if (lateralPosition === -1) return;
553+
554+ if (!currentItem) {
555+ selectItemAt(lateralPosition);
556+ return;
557+ }
558+
559+ var maximumBufferOffset = selectionChangeBuffer * unitProgress;
560+ var proposedItem = indicatorAt(lateralPosition, 0);
561+ if (proposedItem) {
562+ var bufferExceeded = false;
563+
564+ if (proposedItem !== currentItem) {
565+ // Proposed item is not directly adjacent to current?
566+ if (Math.abs(proposedItem.ownIndex - currentItem.ownIndex) > 1) {
567+ bufferExceeded = true;
568+ } else { // no
569+ var currentItemLateralPosition = root.mapToItem(proposedItem, lateralPosition, 0).x;
570+
571+ // Is the distance into proposed item greater than max buffer?
572+ // Proposed item is before current item
573+ if (proposedItem.x < currentItem.x) {
574+ bufferExceeded = (proposedItem.width - currentItemLateralPosition) > maximumBufferOffset;
575+ } else { // After
576+ bufferExceeded = currentItemLateralPosition > maximumBufferOffset;
577+ }
578+ }
579+ if (bufferExceeded) {
580+ selectItemAt(lateralPosition);
581+ }
582+ }
583+ } else {
584+ selectItemAt(lateralPosition);
585+ }
586+ }
587+
588+ function indicatorAt(x, y) {
589+ var item = row.childAt(x, y);
590+ return item && item.hasOwnProperty("ownIndex") ? item : null;
591+ }
592+
593+ function resetCurrentItem() {
594+ d.firstItemSwitch = true;
595+ d.previousItem = undefined;
596+ currentItem = undefined;
597+ }
598+
599+ function setCurrentItemIndex(index) {
600+ for (var i = 0; i < row.children.length; i++) {
601+ var item = row.children[i];
602+ if (item.hasOwnProperty("ownIndex") && item.ownIndex === index) {
603+ if (currentItem !== item) currentItem = item;
604+ break;
605+ }
606+ }
607+ }
608+
609+ function selectItemAt(lateralPosition) {
610+ var item = indicatorAt(lateralPosition, 0);
611+ if (item && item.opacity > 0) {
612+ currentItem = item;
613+ } else {
614+ // Select default item.
615+ var searchIndex = lateralPosition > width ? repeater.count - 1 : 0;
616+
617+ for (var i = 0; i < row.children.length; i++) {
618+ if (row.children[i].hasOwnProperty("ownIndex") && row.children[i].ownIndex === searchIndex) {
619+ item = row.children[i];
620+ break;
621+ }
622+ }
623+ if (currentItem !== item) currentItem = item;
624+ }
625+ }
626+
627+ QtObject {
628+ id: d
629+ property bool firstItemSwitch: true
630+ property var previousItem
631+ property bool forceAlignmentAnimationDisabled: false
632+ }
633+
634+ onCurrentItemChanged: {
635+ if (d.previousItem) {
636+ d.firstItemSwitch = false;
637+ }
638+ d.previousItem = currentItem;
639+ }
640+
641+ Row {
642+ id: row
643+ anchors {
644+ top: parent.top
645+ bottom: parent.bottom
646+ }
647+
648+ // TODO: make this better
649+ // when the width changes, the highlight will lag behind due to animation, so we need to disable the animation
650+ // and adjust the highlight X immediately.
651+ width: implicitWidth
652+ Behavior on width {
653+ SequentialAnimation {
654+ ScriptAction {
655+ script: {
656+ d.forceAlignmentAnimationDisabled = true;
657+ highlight.currentItemX = Qt.binding(function() { return currentItem ? currentItem.x : 0 });
658+ d.forceAlignmentAnimationDisabled = false;
659+ }
660+ }
661+ }
662+ }
663+
664+ Repeater {
665+ id: repeater
666+ model: indicatorsModel
667+ visible: false
668+
669+ onItemRemoved: {
670+ // current item removed.
671+ if (currentItem === item) {
672+ var i = 0;
673+ while (i < row.children.length) {
674+ var childItem = row.children[i];
675+ if (childItem !== item) {
676+ setCurrentItemIndex(i);
677+ break;
678+ }
679+ i++;
680+ }
681+ }
682+ }
683+
684+
685+ delegate: IndicatorItem {
686+ id: indicatorItem
687+ objectName: identifier+"-panelItem"
688+
689+ property int ownIndex: index
690+ property bool overflow: row.width - x > overFlowWidth
691+ property bool hidden: !expanded && (overflow || !indicatorVisible)
692+
693+ height: row.height
694+ expanded: root.expanded
695+ selected: currentItem === this
696+
697+ identifier: model.identifier
698+ busName: indicatorProperties.busName
699+ actionsObjectPath: indicatorProperties.actionsObjectPath
700+ menuObjectPath: indicatorProperties.menuObjectPath
701+
702+ opacity: hidden ? 0.0 : 1.0
703+ Behavior on opacity {
704+ NumberAnimation { duration: UbuntuAnimation.SnapDuration; easing: UbuntuAnimation.StandardEasing }
705+ }
706+
707+ width: (expanded || indicatorVisible) ? implicitWidth : 0
708+
709+ Behavior on width {
710+ NumberAnimation { duration: UbuntuAnimation.SnapDuration; easing: UbuntuAnimation.StandardEasing }
711+ }
712+
713+ Component.onDestruction: {
714+ // current item removed.
715+ if (currentItem === this) {
716+ var i = 0;
717+ while (i < row.children.length) {
718+ var childItem = row.children[i];
719+ if (childItem !== this) {
720+ setCurrentItemIndex(i);
721+ break;
722+ }
723+ i++;
724+ }
725+ }
726+ }
727+ }
728+ }
729+ }
730+
731+ Rectangle {
732+ id: highlight
733+ objectName: "highlight"
734+
735+ anchors.bottom: row.bottom
736+ height: units.dp(2)
737+ color: root.hightlightColor
738+ visible: currentItem !== undefined
739+ opacity: 0.0
740+
741+ width: currentItem ? currentItem.width : 0
742+ Behavior on width {
743+ enabled: !d.firstItemSwitch && expanded
744+ UbuntuNumberAnimation { duration: UbuntuAnimation.FastDuration; easing: UbuntuAnimation.StandardEasing }
745+ }
746+
747+ // micromovements of the highlight line when user moves the finger across the items while pulling
748+ // the handle downwards.
749+ property real highlightCenterOffset: {
750+ if (!currentItem || lateralPosition == -1 || !enableLateralChanges) return 0;
751+
752+ var itemMapped = root.mapToItem(currentItem, lateralPosition, 0);
753+
754+ var distanceFromCenter = itemMapped.x - currentItem.width / 2;
755+ if (distanceFromCenter > 0) {
756+ distanceFromCenter = Math.max(0, distanceFromCenter - currentItem.width / 8);
757+ } else {
758+ distanceFromCenter = Math.min(0, distanceFromCenter + currentItem.width / 8);
759+ }
760+
761+ if (currentItem && currentItem.ownIndex === 0 && distanceFromCenter < 0) {
762+ return 0;
763+ } else if (currentItem && currentItem.ownIndex === repeater.count-1 & distanceFromCenter > 0) {
764+ return 0;
765+ }
766+ return (distanceFromCenter / (currentItem.width / 4)) * units.gu(1);
767+ }
768+ Behavior on highlightCenterOffset {
769+ NumberAnimation { duration: UbuntuAnimation.FastDuration; easing: UbuntuAnimation.StandardEasing }
770+ }
771+
772+ property real currentItemX: currentItem ? currentItem.x : 0
773+ Behavior on currentItemX {
774+ id: currentItemXBehavior
775+ enabled: !d.firstItemSwitch && expanded && !d.forceAlignmentAnimationDisabled
776+ NumberAnimation { duration: UbuntuAnimation.FastDuration; easing: UbuntuAnimation.StandardEasing }
777+ }
778+ x: currentItemX + highlightCenterOffset
779+ }
780+
781+ states: [
782+ State {
783+ name: "minimised"
784+ when: !expanded
785+ },
786+ State {
787+ name: "expanded"
788+ when: expanded
789+ PropertyChanges { target: highlight; opacity: 0.9 }
790+ }
791+ ]
792+
793+ transitions: [
794+ Transition {
795+ PropertyAnimation {
796+ properties: "opacity";
797+ duration: UbuntuAnimation.SnapDuration
798+ easing: UbuntuAnimation.StandardEasing
799+ }
800+ }
801+ ]
802+}
803
804=== renamed file 'qml/Panel/Indicators/DefaultIndicatorPage.qml' => 'qml/Panel/IndicatorPage.qml'
805--- qml/Panel/Indicators/DefaultIndicatorPage.qml 2014-10-10 11:13:26 +0000
806+++ qml/Panel/IndicatorPage.qml 2014-10-21 21:16:05 +0000
807@@ -1,5 +1,5 @@
808 /*
809- * Copyright 2013 Canonical Ltd.
810+ * Copyright 2013-2014 Canonical Ltd.
811 *
812 * This program is free software; you can redistribute it and/or modify
813 * it under the terms of the GNU Lesser General Public License as published by
814@@ -12,16 +12,13 @@
815 *
816 * You should have received a copy of the GNU Lesser General Public License
817 * along with this program. If not, see <http://www.gnu.org/licenses/>.
818- *
819- * Authors:
820- * Renato Araujo Oliveira Filho <renato@canonical.com>
821- * Nick Dedekind <nick.dedekind@canonical.com>
822 */
823
824 import QtQuick 2.0
825 import Ubuntu.Components 0.1 as Components
826 import Unity.Indicators 0.1 as Indicators
827-import "../../Components/Flickables" as Flickables
828+import "Indicators"
829+import "../Components/Flickables" as Flickables
830
831 IndicatorBase {
832 id: main
833@@ -52,13 +49,13 @@
834
835 Connections {
836 target: menuStack.tail
837- onRowsInserted: {
838- if (menuStack.rootMenu !== menuStack.tail && menuStack.tail.get(0, "type") === rootMenuType) {
839- menuStack.rootMenu = menuStack.tail.submenu(0);
840- menuStack.push(menuStack.rootMenu, 0);
841- }
842- }
843- onModelReset: {
844+
845+ // fix async creation with signal from model before it's finished.
846+ Component.onCompleted: update();
847+ onRowsInserted: update();
848+ onModelReset: update();
849+
850+ function update() {
851 if (menuStack.rootMenu !== menuStack.tail && menuStack.tail.get(0, "type") === rootMenuType) {
852 menuStack.rootMenu = menuStack.tail.submenu(0);
853 menuStack.push(menuStack.rootMenu, 0);
854@@ -92,8 +89,6 @@
855
856 // Only allow flicking if the content doesn't fit on the page
857 interactive: contentHeight > height
858- // FIXME - https://bugreports.qt-project.org/browse/QTBUG-41207
859- boundsBehavior: Flickable.StopAtBounds
860
861 property int selectedIndex: -1
862 property bool blockCurrentIndexChange: false
863@@ -126,7 +121,6 @@
864 delegate: Loader {
865 id: loader
866 objectName: "menuItem" + index
867- asynchronous: true
868 width: ListView.view.width
869 visible: status == Loader.Ready
870
871
872=== removed file 'qml/Panel/IndicatorRow.qml'
873--- qml/Panel/IndicatorRow.qml 2014-09-05 15:23:43 +0000
874+++ qml/Panel/IndicatorRow.qml 1970-01-01 00:00:00 +0000
875@@ -1,163 +0,0 @@
876-/*
877- * Copyright (C) 2013 Canonical, Ltd.
878- *
879- * This program is free software; you can redistribute it and/or modify
880- * it under the terms of the GNU General Public License as published by
881- * the Free Software Foundation; version 3.
882- *
883- * This program is distributed in the hope that it will be useful,
884- * but WITHOUT ANY WARRANTY; without even the implied warranty of
885- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
886- * GNU General Public License for more details.
887- *
888- * You should have received a copy of the GNU General Public License
889- * along with this program. If not, see <http://www.gnu.org/licenses/>.
890- */
891-
892-import QtQuick 2.0
893-import Ubuntu.Components 0.1
894-import Unity.Indicators 0.1 as Indicators
895-import "../Components"
896-import "../Components/Flickables" as Flickables
897-
898-Item {
899- id: indicatorRow
900-
901- readonly property alias currentItem : itemView.currentItem
902- readonly property alias currentItemIndex: itemView.currentIndex
903- readonly property alias row: itemView
904- property QtObject indicatorsModel: null
905- property int overFlowWidth: width
906- property bool showAll: false
907- property real currentItemOffset: 0.0
908- property real unitProgress: 0.0
909-
910- width: units.gu(40)
911- height: units.gu(3)
912-
913- function setDefaultItem() {
914- // The leftmost indicator
915- setCurrentItemIndex(0);
916- }
917-
918- function setCurrentItemIndex(index) {
919- itemView.currentIndex = index;
920- }
921-
922- function setCurrentItem(item) {
923- if (item && item.hasOwnProperty("ownIndex")) {
924- itemView.currentIndex = item.ownIndex;
925- } else {
926- itemView.currentIndex = -1;
927- }
928- }
929-
930- Timer {
931- id: allVisible
932- interval: 1000
933-
934- onTriggered: {
935- showAll = false;
936- }
937- }
938-
939- Flickables.ListView {
940- id: itemView
941- objectName: "indicatorRowItems"
942- interactive: false
943- model: indicatorsModel ? indicatorsModel : null
944-
945- width: childrenRect.width
946- height: indicatorRow.height
947- anchors.right: parent.right
948- orientation: ListView.Horizontal
949-
950- property int lastCount: 0
951- onCountChanged: {
952- if (lastCount < count) {
953- showAll = true;
954- allVisible.start();
955- }
956- lastCount = count;
957- }
958-
959- delegate: Item {
960- id: itemWrapper
961- objectName: "item" + index
962- height: indicatorRow.height
963- width: indicatorItem.width
964- opacity: 1 - indicatorRow.unitProgress
965- y: 0
966- state: "standard"
967-
968- property int ownIndex: index
969- property bool highlighted: indicatorRow.unitProgress > 0 ? ListView.isCurrentItem : false
970- property bool dimmed: indicatorRow.unitProgress > 0 ? !ListView.isCurrentItem : false
971-
972- property bool hidden: !showAll && !highlighted && (indicatorRow.state == "locked" || indicatorRow.state == "commit")
973- property bool overflow: row.width - itemWrapper.x > overFlowWidth
974-
975- IndicatorItem {
976- id: indicatorItem
977- identifier: model.identifier
978- height: parent.height
979-
980- dimmed: itemWrapper.dimmed
981-
982- widgetSource: model.widgetSource
983- indicatorProperties : model.indicatorProperties
984- }
985-
986- states: [
987- State {
988- name: "standard"
989- when: !hidden && !overflow && !highlighted
990- },
991- State {
992- name: "highlighted"
993- when: highlighted
994- PropertyChanges { target: itemWrapper; opacity: 1.0 }
995- },
996- State {
997- name: "hidden"
998- when: hidden || overflow
999- PropertyChanges { target: itemWrapper; opacity: 0.0 }
1000- }
1001- ]
1002-
1003- Behavior on opacity { UbuntuNumberAnimation { duration: UbuntuAnimation.BriskDuration } }
1004- }
1005- }
1006-
1007-
1008- Rectangle {
1009- id: highlight
1010- color: Theme.palette.selected.foreground
1011- objectName: "highlight"
1012- height: units.dp(2)
1013- anchors.top: row.bottom
1014- visible: indicatorRow.currentItem != null
1015-
1016- property real intendedX: row.x + (indicatorRow.currentItem != null ? (indicatorRow.currentItem.x - row.originX) + centerOffset : 0)
1017- x: intendedX >= row.x ? (intendedX + width <= row.x + row.width ? intendedX : row.x + row.width - width) : row.x // listview boundaries
1018- width: indicatorRow.currentItem != null ? indicatorRow.currentItem.width : 0
1019-
1020- property real centerOffset: {
1021- if (indicatorRow.currentItemOffset > 0.1) {
1022- return (indicatorRow.currentItemOffset - 0.1) * units.gu(0.4);
1023- } else if (indicatorRow.currentItemOffset < -0.1) {
1024- return (indicatorRow.currentItemOffset + 0.1) * units.gu(0.4);
1025- }
1026- return 0.0;
1027- }
1028-
1029- Behavior on width {
1030- enabled: unitProgress > 0;
1031- UbuntuNumberAnimation { duration: UbuntuAnimation.FastDuration }
1032- }
1033- Behavior on x {
1034- enabled: unitProgress > 0;
1035- UbuntuNumberAnimation { duration: UbuntuAnimation.FastDuration }
1036- }
1037- }
1038-}
1039
1040=== removed file 'qml/Panel/Indicators.qml'
1041--- qml/Panel/Indicators.qml 2014-09-09 13:40:41 +0000
1042+++ qml/Panel/Indicators.qml 1970-01-01 00:00:00 +0000
1043@@ -1,415 +0,0 @@
1044-/*
1045- * Copyright (C) 2013 Canonical, Ltd.
1046- *
1047- * This program is free software; you can redistribute it and/or modify
1048- * it under the terms of the GNU General Public License as published by
1049- * the Free Software Foundation; version 3.
1050- *
1051- * This program is distributed in the hope that it will be useful,
1052- * but WITHOUT ANY WARRANTY; without even the implied warranty of
1053- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1054- * GNU General Public License for more details.
1055- *
1056- * You should have received a copy of the GNU General Public License
1057- * along with this program. If not, see <http://www.gnu.org/licenses/>.
1058- */
1059-
1060-import QtQuick 2.0
1061-import Ubuntu.Components 0.1
1062-import Ubuntu.Gestures 0.1
1063-import Unity.Indicators 0.1 as Indicators
1064-
1065-import "../Components"
1066-import "../Components/ListItems"
1067-import "Indicators"
1068-
1069-Showable {
1070- id: indicators
1071-
1072- property real openedHeight: units.gu(71)
1073- property int panelHeight: units.gu(3)
1074- property alias overFlowWidth: indicatorRow.overFlowWidth
1075- property alias showAll: indicatorRow.showAll
1076- // TODO: This should be sourced by device type (eg "desktop", "tablet", "phone"...)
1077- property string profile: indicatorProfile
1078-
1079- readonly property real hintValue: panelHeight + menuContent.headerHeight
1080- readonly property int lockThreshold: openedHeight / 2
1081- property bool fullyOpened: height == openedHeight
1082- property bool partiallyOpened: height > panelHeight && !fullyOpened
1083- property bool fullyClosed: height <= panelHeight
1084- property bool contentEnabled: true
1085- property bool initalizeItem: true
1086- readonly property alias content: menuContent
1087- property real unitProgress: (height - panelHeight) / (openedHeight - panelHeight)
1088- property bool enableHint: true
1089- property real showHintBottomMargin: 0
1090-
1091- signal showTapped(point position)
1092-
1093- // TODO: Perhaps we need a animation standard for showing/hiding? Each showable seems to
1094- // use its own values. Need to ask design about this.
1095- showAnimation: StandardAnimation {
1096- property: "height"
1097- to: openedHeight
1098- }
1099-
1100- hideAnimation: StandardAnimation {
1101- property: "height"
1102- duration: 350
1103- to: panelHeight
1104- easing.type: Easing.OutCubic
1105- }
1106-
1107- onOpenedHeightChanged: {
1108- if (showAnimation.running) {
1109- showAnimation.restart();
1110- } else if (indicators.shown) {
1111- height = openedHeight;
1112- }
1113- }
1114-
1115- height: panelHeight
1116- onHeightChanged: updateRevealProgressState(indicators.height - panelHeight - showHintBottomMargin, true)
1117-
1118- function updateRevealProgressState(revealProgress, enableRelease) {
1119- if (!showAnimation.running && !hideAnimation.running) {
1120- if (revealProgress === 0) {
1121- indicators.state = "initial";
1122- } else if (enableHint && revealProgress > 0 && revealProgress <= hintValue) {
1123- indicators.state = "hint";
1124- } else if ((!enableHint || revealProgress > hintValue) && revealProgress < lockThreshold) {
1125- indicators.state = "reveal";
1126- } else if (revealProgress >= lockThreshold && lockThreshold > 0) {
1127- indicators.state = "locked";
1128- }
1129- }
1130- }
1131-
1132- function calculateCurrentItem(xValue, useBuffer) {
1133- var rowCoordinates;
1134- var itemCoordinates;
1135- var currentItem;
1136- var distanceFromRightEdge;
1137- var bufferExceeded = false;
1138-
1139- if (indicators.state == "commit" || indicators.state == "locked" || showAnimation.running || hideAnimation.running) return;
1140-
1141- /*
1142- If user drags the indicator handle bar down a distance hintValue or less, this is 0.
1143- If bar is dragged down a distance greater than or equal to lockThreshold, this is 1.
1144- Otherwise it contains the bar's location as a fraction of the distance between hintValue (is 0) and lockThreshold (is 1).
1145- */
1146- var verticalProgress =
1147- MathUtils.clamp((indicators.height - handle.height - hintValue) /
1148- (lockThreshold - hintValue), 0, 1);
1149-
1150- /*
1151- Vertical velocity check. Don't change the indicator if we're moving too quickly.
1152- */
1153- var verticalSpeed = Math.abs(yVelocityCalculator.calculate());
1154- if (verticalSpeed >= 0.05 && !initalizeItem) {
1155- return;
1156- }
1157-
1158- /*
1159- Percentage of an indicator icon's width the user's press can stray horizontally from the
1160- focused icon before we change focus to another icon. E.g. a value of 0.5 means you must
1161- go right a distance of half an icon's width before focus moves to the icon on the right
1162- */
1163- var maxBufferThreshold = 0.5;
1164-
1165- /*
1166- To help users find the indicator of their choice while opening the indicators, we add logic to add a
1167- left/right buffer to each icon so it is harder for the focus to be moved accidentally to another icon,
1168- as the user moves their finger down, but yet allows them to switch indicator if they want.
1169- This buffer is wider the further the user's finger is from the top of the screen.
1170- */
1171- var effectiveBufferThreshold = maxBufferThreshold * verticalProgress;
1172-
1173- rowCoordinates = indicatorRow.mapToItem(indicatorRow.row, xValue, 0);
1174- // get the current delegate
1175- currentItem = indicatorRow.row.itemAt(rowCoordinates.x, 0);
1176- if (currentItem) {
1177- itemCoordinates = indicatorRow.row.mapToItem(currentItem, rowCoordinates.x, 0);
1178- distanceFromRightEdge = (currentItem.width - itemCoordinates.x) / (currentItem.width);
1179- if (currentItem != indicatorRow.currentItem) {
1180- if (Math.abs(currentItem.ownIndex - indicatorRow.currentItemIndex) > 1) {
1181- bufferExceeded = true;
1182- } else {
1183- if (indicatorRow.currentItemIndex < currentItem.ownIndex && distanceFromRightEdge < (1 - effectiveBufferThreshold)) {
1184- bufferExceeded = true;
1185- } else if (indicatorRow.currentItemIndex > currentItem.ownIndex && distanceFromRightEdge > effectiveBufferThreshold) {
1186- bufferExceeded = true;
1187- }
1188- }
1189- if ((!useBuffer || (useBuffer && bufferExceeded)) || indicatorRow.currentItemIndex < 0 || indicatorRow.currentItem == null) {
1190- indicatorRow.setCurrentItem(currentItem);
1191- }
1192-
1193- // need to re-init the distanceFromRightEdge for offset calculation
1194- itemCoordinates = indicatorRow.row.mapToItem(indicatorRow.currentItem, rowCoordinates.x, 0);
1195- distanceFromRightEdge = (indicatorRow.currentItem.width - itemCoordinates.x) / (indicatorRow.currentItem.width);
1196- }
1197- indicatorRow.currentItemOffset = 1 - (distanceFromRightEdge * 2);
1198- } else if (initalizeItem) {
1199- indicatorRow.setDefaultItem();
1200- indicatorRow.currentItemOffset = 0;
1201- }
1202- initalizeItem = indicatorRow.currentItem == null;
1203- }
1204-
1205- // eater
1206- MouseArea {
1207- anchors {
1208- top: parent.top
1209- bottom: handle.bottom
1210- left: parent.left
1211- right: parent.right
1212- }
1213- }
1214-
1215- VisibleIndicators {
1216- id: visibleIndicators
1217- }
1218-
1219- MenuContent {
1220- id: menuContent
1221- objectName: "menuContent"
1222-
1223- anchors {
1224- left: parent.left
1225- right: parent.right
1226- top: indicatorRow.bottom
1227- bottom: handle.top
1228- }
1229- indicatorsModel: visibleIndicators.model
1230- visible: indicators.partiallyOpened || indicators.fullyOpened
1231- clip: indicators.partiallyOpened
1232- enabled: contentEnabled
1233-
1234- //small shadow gradient at bottom of menu
1235- Rectangle {
1236- anchors {
1237- left: parent.left
1238- right: parent.right
1239- bottom: parent.bottom
1240- }
1241- height: units.gu(0.5)
1242- gradient: Gradient {
1243- GradientStop { position: 0.0; color: "transparent" }
1244- GradientStop { position: 1.0; color: "black" }
1245- }
1246- opacity: 0.4
1247- }
1248- }
1249-
1250- Rectangle {
1251- id: handle
1252-
1253- color: menuContent.color
1254-
1255- anchors {
1256- left: parent.left
1257- right: parent.right
1258- bottom: parent.bottom
1259- }
1260- height: Math.max(Math.min(handleImage.height, indicators.height - handleImage.height), 0)
1261- clip: height < handleImage.height
1262- visible: menuContent.visible
1263-
1264- BorderImage {
1265- id: handleImage
1266- source: "graphics/handle.sci"
1267- height: panelHeight
1268- anchors {
1269- left: parent.left
1270- right: parent.right
1271- bottom: parent.bottom
1272- }
1273- }
1274- MouseArea { //prevent clicks passing through
1275- anchors.fill: parent
1276- }
1277- }
1278-
1279- IndicatorRow {
1280- id: indicatorRow
1281- objectName: "indicatorRow"
1282- anchors {
1283- left: parent.left
1284- right: parent.right
1285- }
1286- height: indicators.panelHeight
1287- indicatorsModel: visibleIndicators.model
1288- state: indicators.state
1289- unitProgress: indicators.unitProgress
1290-
1291- EdgeDragArea {
1292- id: rowDragArea
1293- anchors.fill: indicatorRow
1294- direction: Direction.Downwards
1295- maxSilenceTime: 2000
1296- distanceThreshold: 0
1297-
1298- enabled: fullyOpened
1299- onDraggingChanged: {
1300- if (dragging) {
1301- initalizeItem = true;
1302- updateRevealProgressState(Math.max(touchSceneY - panelHeight, hintValue), false);
1303- indicators.calculateCurrentItem(touchX, false);
1304- } else {
1305- indicators.state = "commit";
1306- indicatorRow.currentItemOffset = 0;
1307- }
1308- }
1309-
1310- onTouchXChanged: {
1311- indicators.calculateCurrentItem(touchX, true);
1312- }
1313- onTouchSceneYChanged: {
1314- updateRevealProgressState(Math.max(touchSceneY - panelHeight, hintValue), false);
1315- yVelocityCalculator.trackedPosition = touchSceneY;
1316- }
1317- }
1318- }
1319-
1320- Connections {
1321- target: showAnimation
1322- onRunningChanged: {
1323- if (showAnimation.running) {
1324- indicators.state = "commit";
1325- indicatorRow.currentItemOffset = 0;
1326- }
1327- }
1328- }
1329-
1330- Connections {
1331- target: hideAnimation
1332- onRunningChanged: {
1333- if (hideAnimation.running) {
1334- indicators.state = "initial";
1335- initalizeItem = true;
1336- indicatorRow.currentItemOffset = 0;
1337- }
1338- }
1339- }
1340-
1341- QtObject {
1342- id: d
1343- property bool enableIndexChangeSignal: true
1344- property var activeDragHandle: showDragHandle.dragging ? showDragHandle : hideDragHandle.dragging ? hideDragHandle : null
1345- }
1346-
1347- Connections {
1348- target: menuContent
1349- onCurrentMenuIndexChanged: {
1350- var oldActive = d.enableIndexChangeSignal;
1351- if (!oldActive) return;
1352- d.enableIndexChangeSignal = false;
1353-
1354- indicatorRow.setCurrentItemIndex(menuContent.currentMenuIndex);
1355-
1356- d.enableIndexChangeSignal = oldActive;
1357- }
1358- }
1359-
1360- Connections {
1361- target: indicatorRow
1362- onCurrentItemIndexChanged: {
1363- var oldActive = d.enableIndexChangeSignal;
1364- if (!oldActive) return;
1365- d.enableIndexChangeSignal = false;
1366-
1367- menuContent.setCurrentMenuIndex(indicatorRow.currentItemIndex, fullyOpened || partiallyOpened);
1368-
1369- d.enableIndexChangeSignal = oldActive;
1370- }
1371- }
1372- // connections to the active drag handle
1373- Connections {
1374- target: d.activeDragHandle
1375- onTouchXChanged: {
1376- indicators.calculateCurrentItem(d.activeDragHandle.touchX, true);
1377- }
1378- onTouchSceneYChanged: {
1379- yVelocityCalculator.trackedPosition = d.activeDragHandle.touchSceneY;
1380- }
1381- }
1382-
1383- DragHandle {
1384- id: showDragHandle
1385- anchors.bottom: parent.bottom
1386- // go beyond parent so that it stays reachable, at the top of the screen.
1387- anchors.bottomMargin: showHintBottomMargin
1388- anchors.left: parent.left
1389- anchors.right: parent.right
1390- height: panelHeight
1391- direction: Direction.Downwards
1392- enabled: !indicators.shown && indicators.available
1393- hintDisplacement: enableHint ? indicators.hintValue : 0
1394- autoCompleteDragThreshold: maxTotalDragDistance / 2
1395- stretch: true
1396- maxTotalDragDistance: openedHeight - panelHeight
1397- distanceThreshold: panelHeight
1398-
1399- onTapped: showTapped(Qt.point(touchSceneX, touchSceneY));
1400- }
1401-
1402- DragHandle {
1403- id: hideDragHandle
1404- anchors.fill: handle
1405- direction: Direction.Upwards
1406- enabled: indicators.shown && indicators.available
1407- hintDisplacement: indicators.hintValue
1408- autoCompleteDragThreshold: maxTotalDragDistance / 6
1409- stretch: true
1410- maxTotalDragDistance: openedHeight - panelHeight
1411- distanceThreshold: 0
1412- }
1413-
1414- AxisVelocityCalculator {
1415- id: yVelocityCalculator
1416- }
1417-
1418- states: [
1419- State {
1420- name: "initial"
1421- },
1422- State {
1423- name: "hint"
1424- StateChangeScript {
1425- script: {
1426- if (d.activeDragHandle) {
1427- calculateCurrentItem(d.activeDragHandle.touchX, false);
1428- }
1429- }
1430- }
1431- },
1432- State {
1433- name: "reveal"
1434- extend: "hint"
1435- },
1436- State {
1437- name: "locked"
1438- extend: "hint"
1439- },
1440- State {
1441- name: "commit"
1442- extend: "hint"
1443- }
1444- ]
1445- state: "initial"
1446-
1447- transitions: [
1448- Transition {
1449- NumberAnimation {targets: [indicatorRow, menuContent]; property: "y"; duration: 300; easing.type: Easing.OutCubic}
1450- }
1451- ]
1452-
1453- Component.onCompleted: initialise();
1454- function initialise() {
1455- visibleIndicators.load(profile);
1456- indicatorRow.setDefaultItem();
1457- }
1458-}
1459
1460=== removed file 'qml/Panel/Indicators/DefaultIndicatorWidget.qml'
1461--- qml/Panel/Indicators/DefaultIndicatorWidget.qml 2014-08-20 08:39:09 +0000
1462+++ qml/Panel/Indicators/DefaultIndicatorWidget.qml 1970-01-01 00:00:00 +0000
1463@@ -1,119 +0,0 @@
1464-/*
1465- * Copyright 2013 Canonical Ltd.
1466- *
1467- * This program is free software; you can redistribute it and/or modify
1468- * it under the terms of the GNU Lesser General Public License as published by
1469- * the Free Software Foundation; version 3.
1470- *
1471- * This program is distributed in the hope that it will be useful,
1472- * but WITHOUT ANY WARRANTY; without even the implied warranty of
1473- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1474- * GNU Lesser General Public License for more details.
1475- *
1476- * You should have received a copy of the GNU Lesser General Public License
1477- * along with this program. If not, see <http://www.gnu.org/licenses/>.
1478- *
1479- * Authors:
1480- * Nick Dedekind <nick.dedekind@canonical.com>
1481- */
1482-
1483-import QtQuick 2.0
1484-import Ubuntu.Components 0.1
1485-import Ubuntu.Settings.Components 0.1
1486-
1487-IndicatorBase {
1488- id: indicatorWidget
1489-
1490- property int iconSize: units.gu(2)
1491- property alias leftLabel: itemLeftLabel.text
1492- property alias rightLabel: itemRightLabel.text
1493- property var icons: undefined
1494-
1495- width: itemRow.width
1496- enabled: false
1497-
1498- // FIXME: For now we will enable led indicator support only for messaging indicator
1499- // in the future we should export a led API insted of doing that,
1500- Loader {
1501- id: indicatorLed
1502- // only load source Component if the icons contains the new message icon
1503- source: (indicatorWidget.icons && (String(indicatorWidget.icons).indexOf("indicator-messages-new") != -1)) ? Qt.resolvedUrl("IndicatorsLight.qml") : ""
1504- }
1505-
1506- Row {
1507- id: itemRow
1508- objectName: "itemRow"
1509- anchors {
1510- top: parent.top
1511- bottom: parent.bottom
1512- horizontalCenter: parent.horizontalCenter
1513- }
1514-
1515- Label {
1516- id: itemLeftLabel
1517- width: contentWidth + units.gu(1)
1518- objectName: "leftLabel"
1519- color: Theme.palette.selected.backgroundText
1520- opacity: 0.8
1521- font.family: "Ubuntu"
1522- fontSize: "medium"
1523- anchors.verticalCenter: parent.verticalCenter
1524- visible: text != ""
1525- horizontalAlignment: Text.AlignHCenter
1526- }
1527-
1528- Row {
1529- id: iconRow
1530- anchors {
1531- top: parent.top
1532- bottom: parent.bottom
1533- }
1534-
1535- Repeater {
1536- model: indicatorWidget.icons
1537-
1538- Item {
1539- width: itemImage.width + units.gu(1)
1540- height: iconRow.height
1541-
1542- StatusIcon {
1543- id: itemImage
1544- height: indicatorWidget.iconSize
1545- anchors.centerIn: parent
1546- source: modelData
1547- sets: ["status", "actions"]
1548- color: "#CCCCCC"
1549- }
1550- }
1551- }
1552- }
1553-
1554- Label {
1555- id: itemRightLabel
1556- width: contentWidth + units.gu(1)
1557- objectName: "rightLabel"
1558- color: Theme.palette.selected.backgroundText
1559- opacity: 0.8
1560- font.family: "Ubuntu"
1561- fontSize: "medium"
1562- anchors.verticalCenter: parent.verticalCenter
1563- visible: text != ""
1564- horizontalAlignment: Text.AlignHCenter
1565- }
1566- }
1567-
1568- onRootActionStateChanged: {
1569- if (rootActionState == undefined) {
1570- leftLabel = "";
1571- rightLabel = "";
1572- icons = undefined;
1573- enabled = false;
1574- return;
1575- }
1576-
1577- leftLabel = rootActionState.leftLabel ? rootActionState.leftLabel : "";
1578- rightLabel = rootActionState.rightLabel ? rootActionState.rightLabel : "";
1579- icons = rootActionState.icons;
1580- enabled = rootActionState.visible;
1581- }
1582-}
1583
1584=== modified file 'qml/Panel/Indicators/IndicatorBase.qml'
1585--- qml/Panel/Indicators/IndicatorBase.qml 2014-10-21 21:16:04 +0000
1586+++ qml/Panel/Indicators/IndicatorBase.qml 2014-10-21 21:16:05 +0000
1587@@ -23,8 +23,6 @@
1588 Item {
1589 id: indicatorItem
1590
1591- enabled: menuObjectPath != ""
1592-
1593 //const
1594 property string identifier
1595 property string busName
1596@@ -32,8 +30,6 @@
1597 property string menuObjectPath
1598 property string rootMenuType: "com.canonical.indicator.root"
1599
1600- property string deviceMenuObjectPath: menuObjectPath
1601-
1602 property alias menuModel: cachedModel.model
1603 property alias rootActionState: rootAction
1604
1605@@ -41,7 +37,7 @@
1606 id: cachedModel
1607 busName: indicatorItem.busName
1608 actions: { "indicator": indicatorItem.actionsObjectPath }
1609- menuObjectPath: indicatorItem.deviceMenuObjectPath
1610+ menuObjectPath: indicatorItem.menuObjectPath
1611 }
1612
1613 RootActionState {
1614
1615=== modified file 'qml/Panel/Indicators/IndicatorDelegate.qml'
1616--- qml/Panel/Indicators/IndicatorDelegate.qml 2014-07-25 17:52:39 +0000
1617+++ qml/Panel/Indicators/IndicatorDelegate.qml 2014-10-21 21:16:05 +0000
1618@@ -20,6 +20,6 @@
1619 import QtQuick 2.0
1620
1621 IndicatorBase {
1622- enabled: rootActionState.visible
1623- property string title: rootActionState.title
1624+ readonly property bool indicatorVisible: rootActionState.indicatorVisible
1625+ readonly property string title: rootActionState.title
1626 }
1627
1628=== modified file 'qml/Panel/Indicators/VisibleIndicators.qml'
1629--- qml/Panel/Indicators/VisibleIndicators.qml 2014-09-29 10:24:58 +0000
1630+++ qml/Panel/Indicators/VisibleIndicators.qml 2014-10-21 21:16:05 +0000
1631@@ -24,6 +24,10 @@
1632 Item {
1633 property SortFilterProxyModel model: filterModel
1634
1635+ function initialise(profile) {
1636+ indicatorsModel.load(profile);
1637+ }
1638+
1639 SortFilterProxyModel {
1640 id: filterModel
1641 filterRole: Indicators.IndicatorsModelRole.IsVisible
1642@@ -36,7 +40,6 @@
1643 }
1644 }
1645
1646-
1647 Indicators.IndicatorsModel {
1648 id: indicatorsModel
1649 }
1650@@ -78,8 +81,4 @@
1651 }
1652 }
1653 }
1654-
1655- function load(profile) {
1656- indicatorsModel.load(profile);
1657- }
1658 }
1659
1660=== renamed file 'qml/Panel/Indicators/client/IndicatorsPage.qml' => 'qml/Panel/Indicators/client/IndicatorRepresentation.qml'
1661--- qml/Panel/Indicators/client/IndicatorsPage.qml 2013-08-14 09:07:45 +0000
1662+++ qml/Panel/Indicators/client/IndicatorRepresentation.qml 2014-10-21 21:16:05 +0000
1663@@ -21,13 +21,13 @@
1664 import QtQuick 2.0
1665 import Ubuntu.Components 0.1
1666 import Ubuntu.Components.ListItems 0.1 as ListItem
1667+import "../.."
1668
1669 Page {
1670- id: page
1671+ id: root
1672
1673 title: indicatorProperties && indicatorProperties.title ? indicatorProperties.title : ""
1674 property variant indicatorProperties
1675- property string pageSource : pageLoader.source
1676
1677 anchors.fill: parent
1678
1679@@ -44,6 +44,7 @@
1680 id: pageLoader
1681 objectName: "pageLoader"
1682 clip:true
1683+ asynchronous: true
1684
1685 Rectangle {
1686 anchors.fill: pageLoader
1687@@ -58,15 +59,25 @@
1688 topMargin: units.gu(2)
1689 bottomMargin: units.gu(2)
1690 }
1691- source : visualCheck.checked ? page.pageSource : "IndicatorsTree.qml"
1692+ sourceComponent: visualCheck.checked ? page : tree
1693
1694- onLoaded: {
1695- for(var pName in indicatorProperties) {
1696- if (item.hasOwnProperty(pName)) {
1697- item[pName] = indicatorProperties[pName];
1698- }
1699- }
1700- item.start();
1701+ Component {
1702+ id: page
1703+ IndicatorPage {
1704+ identifier: model.identifier
1705+ busName: indicatorProperties.busName
1706+ actionsObjectPath: indicatorProperties.actionsObjectPath
1707+ menuObjectPath: indicatorProperties.menuObjectPath
1708+ }
1709+ }
1710+ Component {
1711+ id: tree
1712+ IndicatorsTree {
1713+ identifier: model.identifier
1714+ busName: indicatorProperties.busName
1715+ actionsObjectPath: indicatorProperties.actionsObjectPath
1716+ menuObjectPath: indicatorProperties.menuObjectPath
1717+ }
1718 }
1719 }
1720
1721@@ -85,7 +96,7 @@
1722 left: parent.left
1723 }
1724 text: "Back"
1725- onClicked: page.pageStack.reset()
1726+ onClicked: root.pageStack.reset()
1727 }
1728 }
1729 }
1730
1731=== modified file 'qml/Panel/Indicators/client/IndicatorsList.qml'
1732--- qml/Panel/Indicators/client/IndicatorsList.qml 2014-09-05 15:23:43 +0000
1733+++ qml/Panel/Indicators/client/IndicatorsList.qml 2014-10-21 21:16:05 +0000
1734@@ -58,8 +58,8 @@
1735 text: identifier
1736
1737 onClicked: {
1738- var new_page = Qt.createComponent("IndicatorsPage.qml");
1739- page.pageStack.push(new_page.createObject(pages), {"indicatorProperties" : model.indicatorProperties, "pageSource" : model.pageSource});
1740+ var new_page = Qt.createComponent("IndicatorRepresentation.qml");
1741+ page.pageStack.push(new_page.createObject(pages), {"indicatorProperties" : model.indicatorProperties });
1742 }
1743 }
1744 }
1745
1746=== modified file 'qml/Panel/Indicators/client/IndicatorsTree.qml'
1747--- qml/Panel/Indicators/client/IndicatorsTree.qml 2014-09-05 15:23:43 +0000
1748+++ qml/Panel/Indicators/client/IndicatorsTree.qml 2014-10-21 21:16:05 +0000
1749@@ -20,37 +20,15 @@
1750 import QtQuick 2.0
1751 import Ubuntu.Components 0.1
1752 import Unity.Indicators 0.1 as Indicators
1753-import QMenuModel 0.1
1754-import Ubuntu.Components.ListItems 0.1 as ListItem
1755+import ".."
1756 import "../../../Components/Flickables" as Flickables
1757
1758-Page {
1759- id: page
1760- anchors.fill: parent
1761-
1762- property string busName: unityModel.busName
1763- property string actionsObjectPath
1764- property string menuObjectPath
1765-
1766- property string deviceMenuObjectPath: menuObjectPath
1767-
1768- function start() {
1769- }
1770-
1771- UnityMenuModel {
1772- id: unityModel
1773- busName: page.busName
1774- actions: { "indicator": page.actionsObjectPath }
1775- menuObjectPath: page.deviceMenuObjectPath
1776- }
1777-
1778- Indicators.RootActionState {
1779- menu: unityModel
1780- }
1781+IndicatorBase {
1782+ id: root
1783
1784 Indicators.ModelPrinter {
1785 id: printer
1786- model: unityModel
1787+ model: root.menuModel
1788 }
1789
1790 Flickables.Flickable {
1791
1792=== added file 'qml/Panel/IndicatorsBar.qml'
1793--- qml/Panel/IndicatorsBar.qml 1970-01-01 00:00:00 +0000
1794+++ qml/Panel/IndicatorsBar.qml 2014-10-21 21:16:05 +0000
1795@@ -0,0 +1,269 @@
1796+/*
1797+ * Copyright (C) 2014 Canonical, Ltd.
1798+ *
1799+ * This program is free software; you can redistribute it and/or modify
1800+ * it under the terms of the GNU General Public License as published by
1801+ * the Free Software Foundation; version 3.
1802+ *
1803+ * This program is distributed in the hope that it will be useful,
1804+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1805+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1806+ * GNU General Public License for more details.
1807+ *
1808+ * You should have received a copy of the GNU General Public License
1809+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1810+ */
1811+
1812+import QtQuick 2.2
1813+import Ubuntu.Components 1.1
1814+import "../Components"
1815+
1816+Item {
1817+ id: root
1818+ property alias expanded: row.expanded
1819+ property alias interactive: flickable.interactive
1820+ property alias indicatorsModel: row.indicatorsModel
1821+ property alias unitProgress: row.unitProgress
1822+ property alias enableLateralChanges: row.enableLateralChanges
1823+ property alias overFlowWidth: row.overFlowWidth
1824+ readonly property alias currentItemIndex: row.currentItemIndex
1825+ property real lateralPosition: -1
1826+
1827+ function selectItemAt(lateralPosition) {
1828+ if (!expanded) {
1829+ row.resetCurrentItem();
1830+ }
1831+ var mapped = root.mapToItem(row, lateralPosition, 0);
1832+ row.selectItemAt(mapped.x);
1833+ }
1834+
1835+ function setCurrentItemIndex(index) {
1836+ if (!expanded) {
1837+ row.resetCurrentItem();
1838+ }
1839+ row.setCurrentItemIndex(index);
1840+ }
1841+
1842+ function addScrollOffset(scrollAmmout) {
1843+ if (scrollAmmout < 0) { // left scroll
1844+ if (flickable.contentX < 0) return; // already off the left.
1845+ if (flickable.contentX + scrollAmmout < 0) scrollAmmout = -flickable.contentX; // going to be off the left
1846+ } else { // right scroll
1847+ if (flickable.contentX + flickable.width > row.width) return; // already off the right.
1848+ if (flickable.contentX + flickable.width + scrollAmmout > row.width) { // going to be off the right
1849+ scrollAmmout = row.width - (flickable.contentX + flickable.width);
1850+ }
1851+ }
1852+ d.scrollOffset = d.scrollOffset + scrollAmmout;
1853+ }
1854+
1855+ QtObject {
1856+ id: d
1857+ property var initialItem
1858+ // the non-expanded distance from row offset to center of initial item
1859+ property real originalDistanceFromRight: -1
1860+
1861+ // calculate the distance from row offset to center of initial item
1862+ property real distanceFromRight: {
1863+ if (originalDistanceFromRight == -1) return 0;
1864+ if (!initialItem) return 0;
1865+ return row.width - initialItem.x - initialItem.width /2;
1866+ }
1867+
1868+ // offset to the intially selected expanded item
1869+ property real rowOffset: 0
1870+ property real scrollOffset: 0
1871+ property real alignmentAdjustment: 0
1872+ property real combinedOffset: 0
1873+
1874+ // when the scroll offset changes, we need to reclaculate the relative lateral position
1875+ onScrollOffsetChanged: root.lateralPositionChanged()
1876+
1877+ onInitialItemChanged: {
1878+ originalDistanceFromRight = initialItem ? (row.width - initialItem.x - initialItem.width/2) : -1;
1879+ }
1880+
1881+ Behavior on alignmentAdjustment {
1882+ NumberAnimation { duration: UbuntuAnimation.BriskDuration; easing: UbuntuAnimation.StandardEasing}
1883+ }
1884+
1885+ function alignIndicators() {
1886+ flickable.resetContentXComponents();
1887+
1888+ if (expanded && !flickable.moving) {
1889+
1890+ // gap between left and row?
1891+ if (flickable.contentX < 0) {
1892+ d.alignmentAdjustment += flickable.contentX;
1893+ // gap between right and row?
1894+ } else if (flickable.contentX + flickable.width > row.width) {
1895+ // row width is less than flickable
1896+ if (row.width < flickable.width) {
1897+ d.alignmentAdjustment += flickable.contentX;
1898+ } else {
1899+ d.alignmentAdjustment += ((flickable.contentX + flickable.width) - row.width);
1900+ }
1901+ // current item overlap on left
1902+ } else if (row.currentItem && row.currentItem.x < flickable.contentX) {
1903+ d.alignmentAdjustment -= (row.currentItem.x - flickable.contentX);
1904+ // current item overlap on right
1905+ } else if (row.currentItem && row.currentItem.x + row.currentItem.width > flickable.contentX + flickable.width) {
1906+ d.alignmentAdjustment -= ((row.currentItem.x + row.currentItem.width) - (flickable.contentX + flickable.width));
1907+ }
1908+ }
1909+ }
1910+ }
1911+
1912+ Rectangle {
1913+ id: grayLine
1914+ height: units.dp(2)
1915+ width: parent.width
1916+ anchors.bottom: parent.bottom
1917+
1918+ color: "#4c4c4c"
1919+ opacity: expanded ? 1.0 : 0.0
1920+ Behavior on opacity { NumberAnimation { duration: UbuntuAnimation.SnapDuration } }
1921+ }
1922+
1923+ Item {
1924+ id: rowContainer
1925+ anchors.fill: parent
1926+ clip: expanded || row.width > rowContainer.width
1927+
1928+ Flickable {
1929+ id: flickable
1930+ objectName: "flickable"
1931+
1932+ anchors.fill: parent
1933+ contentWidth: row.width
1934+ interactive: false
1935+ // align right + offset from row selection + scrolling
1936+ contentX: row.width - flickable.width - d.combinedOffset
1937+
1938+ // contentX can change by user interaction as well as user offset changes
1939+ // This function re-aligns the offsets so that the offsets match the contentX
1940+ function resetContentXComponents() {
1941+ d.scrollOffset += (flickable.contentX - (row.width - flickable.width - d.combinedOffset));
1942+ }
1943+
1944+ rebound: Transition {
1945+ NumberAnimation {
1946+ properties: "x"
1947+ duration: 600
1948+ easing.type: Easing.OutCubic
1949+ }
1950+ }
1951+
1952+ IndicatorItemRow {
1953+ id: row
1954+ objectName: "indicatorItemRow"
1955+ anchors {
1956+ top: parent.top
1957+ bottom: parent.bottom
1958+ }
1959+
1960+ lateralPosition: {
1961+ if (root.lateralPosition == -1) return -1;
1962+
1963+ var mapped = root.mapToItem(row, root.lateralPosition, 0);
1964+ return Math.min(Math.max(mapped.x, 0), row.width);
1965+ }
1966+
1967+ onCurrentItemChanged: {
1968+ if (!currentItem) d.initialItem = undefined;
1969+ else if (!d.initialItem) d.initialItem = currentItem;
1970+ }
1971+
1972+ MouseArea {
1973+ anchors.fill: parent
1974+ enabled: root.expanded
1975+ onClicked: {
1976+ row.selectItemAt(mouse.x);
1977+ d.alignIndicators();
1978+ }
1979+ }
1980+ }
1981+
1982+ }
1983+ }
1984+
1985+ Timer {
1986+ id: alignmentTimer
1987+ interval: UbuntuAnimation.FastDuration // enough for row animation.
1988+ repeat: false
1989+
1990+ onTriggered: d.alignIndicators();
1991+ }
1992+
1993+ states: [
1994+ State {
1995+ name: "minimized"
1996+ when: !expanded
1997+ PropertyChanges {
1998+ target: d
1999+ rowOffset: 0
2000+ scrollOffset: 0
2001+ alignmentAdjustment: 0
2002+ combinedOffset: 0
2003+ restoreEntryValues: false
2004+ }
2005+ },
2006+ State {
2007+ name: "expanded"
2008+ when: expanded && !interactive
2009+
2010+ PropertyChanges {
2011+ target: d
2012+ combinedOffset: rowOffset + alignmentAdjustment - scrollOffset
2013+ }
2014+ PropertyChanges {
2015+ target: d
2016+ rowOffset: {
2017+ if (!initialItem) return 0;
2018+ if (distanceFromRight - initialItem.width <= 0) return 0;
2019+
2020+ var rowOffset = distanceFromRight - originalDistanceFromRight;
2021+ return rowOffset;
2022+ }
2023+ restoreEntryValues: false
2024+ }
2025+ }
2026+ , State {
2027+ name: "interactive"
2028+ when: expanded && interactive
2029+
2030+ StateChangeScript {
2031+ script: {
2032+ // don't use row offset anymore.
2033+ d.scrollOffset -= d.rowOffset;
2034+ d.rowOffset = 0;
2035+ d.initialItem = undefined;
2036+ alignmentTimer.start();
2037+ }
2038+ }
2039+ PropertyChanges {
2040+ target: d
2041+ combinedOffset: rowOffset + alignmentAdjustment - scrollOffset
2042+ restoreEntryValues: false
2043+ }
2044+ }
2045+ ]
2046+
2047+ transitions: [
2048+ Transition {
2049+ from: "expanded"
2050+ to: "minimized"
2051+ PropertyAction {
2052+ target: d
2053+ properties: "rowOffset, scrollOffset, alignmentAdjustment"
2054+ value: 0
2055+ }
2056+ PropertyAnimation {
2057+ target: d
2058+ properties: "combinedOffset"
2059+ duration: UbuntuAnimation.SnapDuration
2060+ easing: UbuntuAnimation.StandardEasing
2061+ }
2062+ }
2063+ ]
2064+}
2065
2066=== added file 'qml/Panel/IndicatorsMenu.qml'
2067--- qml/Panel/IndicatorsMenu.qml 1970-01-01 00:00:00 +0000
2068+++ qml/Panel/IndicatorsMenu.qml 2014-10-21 21:16:05 +0000
2069@@ -0,0 +1,318 @@
2070+/*
2071+ * Copyright (C) 2014 Canonical, Ltd.
2072+ *
2073+ * This program is free software; you can redistribute it and/or modify
2074+ * it under the terms of the GNU General Public License as published by
2075+ * the Free Software Foundation; version 3.
2076+ *
2077+ * This program is distributed in the hope that it will be useful,
2078+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2079+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2080+ * GNU General Public License for more details.
2081+ *
2082+ * You should have received a copy of the GNU General Public License
2083+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2084+ */
2085+
2086+import QtQuick 2.2
2087+import Ubuntu.Components 1.1
2088+import Ubuntu.Gestures 0.1
2089+import "../Components"
2090+
2091+Showable {
2092+ id: root
2093+ property alias indicatorsModel: bar.indicatorsModel
2094+ property alias showDragHandle: __showDragHandle
2095+ property alias hideDragHandle: __hideDragHandle
2096+ property alias overFlowWidth: bar.overFlowWidth
2097+ property alias verticalVelocityThreshold: yVelocityCalculator.velocityThreshold
2098+ property int minimizedPanelHeight: units.gu(3)
2099+ property int expandedPanelHeight: units.gu(7)
2100+ property real openedHeight: units.gu(71)
2101+ readonly property real unitProgress: Math.max(0, (height - minimizedPanelHeight) / (openedHeight - minimizedPanelHeight))
2102+ readonly property bool fullyOpened: unitProgress >= 1
2103+ readonly property bool partiallyOpened: unitProgress > 0 && unitProgress < 1.0
2104+ readonly property bool fullyClosed: unitProgress == 0
2105+ property bool enableHint: true
2106+ property bool contentEnabled: true
2107+ property color panelColor: "black"
2108+
2109+ signal showTapped(point position)
2110+
2111+ // TODO: Perhaps we need a animation standard for showing/hiding? Each showable seems to
2112+ // use its own values. Need to ask design about this.
2113+ showAnimation: StandardAnimation {
2114+ property: "height"
2115+ to: openedHeight
2116+ duration: UbuntuAnimation.BriskDuration
2117+ easing.type: Easing.OutCubic
2118+ }
2119+
2120+ hideAnimation: StandardAnimation {
2121+ property: "height"
2122+ to: minimizedPanelHeight
2123+ duration: UbuntuAnimation.BriskDuration
2124+ easing.type: Easing.OutCubic
2125+ }
2126+
2127+ height: minimizedPanelHeight
2128+
2129+ onUnitProgressChanged: d.updateState()
2130+ clip: root.partiallyOpened
2131+
2132+ // eater
2133+ MouseArea {
2134+ anchors.fill: parent
2135+ }
2136+
2137+ MenuContent {
2138+ id: content
2139+ objectName: "menuContent"
2140+
2141+ anchors {
2142+ left: parent.left
2143+ right: parent.right
2144+ top: bar.bottom
2145+ }
2146+ height: openedHeight - bar.height - handle.height
2147+ indicatorsModel: root.indicatorsModel
2148+ visible: root.unitProgress > 0
2149+ enabled: contentEnabled
2150+ currentMenuIndex: bar.currentItemIndex
2151+ }
2152+
2153+ Handle {
2154+ id: handle
2155+ anchors {
2156+ left: parent.left
2157+ right: parent.right
2158+ bottom: parent.bottom
2159+ }
2160+ height: units.gu(2)
2161+ active: d.activeDragHandle ? true : false
2162+
2163+ //small shadow gradient at bottom of menu
2164+ Rectangle {
2165+ anchors {
2166+ left: parent.left
2167+ right: parent.right
2168+ bottom: parent.top
2169+ }
2170+ height: units.gu(0.5)
2171+ gradient: Gradient {
2172+ GradientStop { position: 0.0; color: "transparent" }
2173+ GradientStop { position: 1.0; color: "black" }
2174+ }
2175+ opacity: 0.3
2176+ }
2177+ }
2178+
2179+ Rectangle {
2180+ anchors.fill: bar
2181+ color: panelColor
2182+ }
2183+
2184+ IndicatorsBar {
2185+ id: bar
2186+ objectName: "indicatorsBar"
2187+
2188+ anchors {
2189+ left: parent.left
2190+ right: parent.right
2191+ }
2192+ expanded: false
2193+ enableLateralChanges: false
2194+ lateralPosition: -1
2195+ unitProgress: root.unitProgress
2196+
2197+ height: expanded ? expandedPanelHeight : minimizedPanelHeight
2198+ Behavior on height { NumberAnimation { duration: UbuntuAnimation.SnapDuration; easing: UbuntuAnimation.StandardEasing } }
2199+ }
2200+
2201+ ScrollCalculator {
2202+ id: leftScroller
2203+ width: units.gu(5)
2204+ anchors.left: bar.left
2205+ height: bar.height
2206+
2207+ forceScrollingPercentage: 0.33
2208+ stopScrollThreshold: units.gu(0.75)
2209+ direction: Qt.RightToLeft
2210+ lateralPosition: -1
2211+
2212+ onScroll: bar.addScrollOffset(-scrollAmount);
2213+ }
2214+
2215+ ScrollCalculator {
2216+ id: rightScroller
2217+ width: units.gu(5)
2218+ anchors.right: bar.right
2219+ height: bar.height
2220+
2221+ forceScrollingPercentage: 0.33
2222+ stopScrollThreshold: units.gu(0.75)
2223+ direction: Qt.LeftToRight
2224+ lateralPosition: -1
2225+
2226+ onScroll: bar.addScrollOffset(scrollAmount);
2227+ }
2228+
2229+ DragHandle {
2230+ id: __showDragHandle
2231+ anchors.bottom: parent.bottom
2232+ anchors.left: parent.left
2233+ anchors.right: parent.right
2234+ height: minimizedPanelHeight
2235+ direction: Direction.Downwards
2236+ enabled: !root.shown && root.available
2237+ autoCompleteDragThreshold: maxTotalDragDistance / 2
2238+ stretch: true
2239+ distanceThreshold: minimizedPanelHeight
2240+ onTapped: showTapped(Qt.point(touchSceneX, touchSceneY));
2241+
2242+ // using hint regulates minimum to hint displacement, but in fullscreen mode, we need to do it manually.
2243+ overrideStartValue: enableHint ? minimizedPanelHeight : expandedPanelHeight + handle.height
2244+ maxTotalDragDistance: openedHeight - (enableHint ? minimizedPanelHeight : expandedPanelHeight + handle.height)
2245+ hintDisplacement: enableHint ? expandedPanelHeight - minimizedPanelHeight + handle.height : 0
2246+ }
2247+
2248+ DragHandle {
2249+ id: __hideDragHandle
2250+ anchors.fill: handle
2251+ direction: Direction.Upwards
2252+ enabled: root.shown && root.available
2253+ hintDisplacement: units.gu(3)
2254+ autoCompleteDragThreshold: maxTotalDragDistance / 6
2255+ stretch: true
2256+ maxTotalDragDistance: openedHeight - expandedPanelHeight - handle.height
2257+ distanceThreshold: 0
2258+
2259+ onTouchSceneXChanged: {
2260+ if (root.state === "locked") {
2261+ d.xDisplacementSinceLock += (touchSceneX - d.lastHideTouchSceneX)
2262+ d.lastHideTouchSceneX = touchSceneX;
2263+ }
2264+ }
2265+ }
2266+
2267+ PanelVelocityCalculator {
2268+ id: yVelocityCalculator
2269+ velocityThreshold: d.hasCommitted ? 0.1 : 0.3
2270+ trackedValue: d.activeDragHandle ? d.activeDragHandle.touchSceneY : 0
2271+
2272+ onVelocityAboveThresholdChanged: d.updateState()
2273+ }
2274+
2275+ Connections {
2276+ target: showAnimation
2277+ onRunningChanged: {
2278+ if (showAnimation.running) {
2279+ root.state = "commit";
2280+ }
2281+ }
2282+ }
2283+
2284+ Connections {
2285+ target: hideAnimation
2286+ onRunningChanged: {
2287+ if (hideAnimation.running) {
2288+ root.state = "initial";
2289+ }
2290+ }
2291+ }
2292+
2293+ QtObject {
2294+ id: d
2295+ property var activeDragHandle: showDragHandle.dragging ? showDragHandle : hideDragHandle.dragging ? hideDragHandle : null
2296+ property bool hasCommitted: false
2297+ property real lastHideTouchSceneX: 0
2298+ property real xDisplacementSinceLock: 0
2299+ onXDisplacementSinceLockChanged: d.updateState()
2300+
2301+ property real rowMappedLateralPosition: {
2302+ if (!d.activeDragHandle) return -1;
2303+ return d.activeDragHandle.mapToItem(bar, d.activeDragHandle.touchX, 0).x;
2304+ }
2305+
2306+ function updateState() {
2307+ if (!showAnimation.running && !hideAnimation.running) {
2308+ if (unitProgress <= 0) {
2309+ root.state = "initial";
2310+ // lock indicator if we've been committed and aren't moving too much laterally or too fast up.
2311+ } else if (d.hasCommitted && (Math.abs(d.xDisplacementSinceLock) < units.gu(2) || yVelocityCalculator.velocityAboveThreshold)) {
2312+ root.state = "locked";
2313+ } else {
2314+ root.state = "reveal";
2315+ }
2316+ }
2317+ }
2318+ }
2319+
2320+ states: [
2321+ State {
2322+ name: "initial"
2323+ PropertyChanges { target: d; hasCommitted: false; restoreEntryValues: false }
2324+ },
2325+ State {
2326+ name: "reveal"
2327+ StateChangeScript {
2328+ script: {
2329+ yVelocityCalculator.reset();
2330+ // initial item selection
2331+ if (!d.hasCommitted) bar.selectItemAt(d.activeDragHandle ? d.activeDragHandle.touchX : -1);
2332+ d.hasCommitted = false;
2333+ }
2334+ }
2335+ PropertyChanges {
2336+ target: bar
2337+ expanded: true
2338+ // changes to lateral touch position effect which indicator is selected
2339+ lateralPosition: d.rowMappedLateralPosition
2340+ // vertical velocity determines if changes in lateral position has an effect
2341+ enableLateralChanges: d.activeDragHandle &&
2342+ !yVelocityCalculator.velocityAboveThreshold
2343+ }
2344+ // left scroll bar handling
2345+ PropertyChanges {
2346+ target: leftScroller
2347+ lateralPosition: {
2348+ if (!d.activeDragHandle) return -1;
2349+ var mapped = d.activeDragHandle.mapToItem(leftScroller, d.activeDragHandle.touchX, 0);
2350+ return mapped.x;
2351+ }
2352+ }
2353+ // right scroll bar handling
2354+ PropertyChanges {
2355+ target: rightScroller
2356+ lateralPosition: {
2357+ if (!d.activeDragHandle) return -1;
2358+ var mapped = d.activeDragHandle.mapToItem(rightScroller, d.activeDragHandle.touchX, 0);
2359+ return mapped.x;
2360+ }
2361+ }
2362+ },
2363+ State {
2364+ name: "locked"
2365+ StateChangeScript {
2366+ script: {
2367+ d.xDisplacementSinceLock = 0;
2368+ d.lastHideTouchSceneX = hideDragHandle.touchSceneX;
2369+ }
2370+ }
2371+ PropertyChanges { target: bar; expanded: true }
2372+ },
2373+ State {
2374+ name: "commit"
2375+ extend: "locked"
2376+ PropertyChanges { target: bar; interactive: true }
2377+ PropertyChanges {
2378+ target: d;
2379+ hasCommitted: true
2380+ lastHideTouchSceneX: 0
2381+ xDisplacementSinceLock: 0
2382+ restoreEntryValues: false
2383+ }
2384+ }
2385+ ]
2386+ state: "initial"
2387+}
2388
2389=== modified file 'qml/Panel/MenuContent.qml'
2390--- qml/Panel/MenuContent.qml 2014-10-10 11:13:26 +0000
2391+++ qml/Panel/MenuContent.qml 2014-10-21 21:16:05 +0000
2392@@ -1,5 +1,5 @@
2393 /*
2394- * Copyright (C) 2013 Canonical, Ltd.
2395+ * Copyright (C) 2013-2014 Canonical, Ltd.
2396 *
2397 * This program is free software; you can redistribute it and/or modify
2398 * it under the terms of the GNU General Public License as published by
2399@@ -14,126 +14,69 @@
2400 * along with this program. If not, see <http://www.gnu.org/licenses/>.
2401 */
2402
2403-import QtQuick 2.0
2404+import QtQuick 2.2
2405 import QtQuick.Layouts 1.1
2406 import Ubuntu.Components 1.1
2407 import Unity.Indicators 0.1 as Indicators
2408 import Utils 0.1
2409 import "../Components"
2410 import "../Components/Flickables" as Flickables
2411-import "Indicators"
2412
2413 Rectangle {
2414 id: content
2415
2416 property QtObject indicatorsModel: null
2417- readonly property alias currentMenuIndex: listViewHeader.currentIndex
2418+ property int currentMenuIndex: -1
2419 color: "#221e1c" // FIXME not in palette yet
2420- property real headerHeight: listViewHeader.height
2421
2422 width: units.gu(40)
2423 height: units.gu(42)
2424
2425- function setCurrentMenuIndex(index, animate) {
2426- // FIXME - https://bugreports.qt-project.org/browse/QTBUG-41229
2427- listViewHeader.currentIndex = -1;
2428- listViewHeader.currentIndex = index;
2429- }
2430-
2431- Flickables.ListView {
2432- id: listViewHeader
2433- objectName: "indicatorsHeaderListView"
2434- model: content.indicatorsModel
2435- clip: true
2436-
2437- anchors {
2438- left: parent.left
2439- right: parent.right
2440- }
2441- height: units.gu(8.5)
2442-
2443- highlightFollowsCurrentItem: true
2444- highlightMoveDuration: 0
2445-
2446- orientation: ListView.Horizontal
2447- snapMode: ListView.SnapOneItem
2448- highlightRangeMode: ListView.StrictlyEnforceRange
2449- boundsBehavior: Flickable.StopAtBounds
2450- // Load all the indicator menus (a big number)
2451- cacheBuffer: 1073741823
2452-
2453- delegate: Header {
2454- width: ListView.view.width
2455- height: implicitHeight
2456-
2457- title: indicatorDelegate.title !== "" ? indicatorDelegate.title : identifier
2458-
2459- IndicatorDelegate {
2460- id: indicatorDelegate
2461- Component.onCompleted: {
2462- for(var pName in indicatorProperties) {
2463- if (indicatorDelegate.hasOwnProperty(pName)) {
2464- indicatorDelegate[pName] = indicatorProperties[pName];
2465- }
2466- }
2467- }
2468- }
2469- }
2470+ onCurrentMenuIndexChanged: {
2471+ listViewContent.currentIndex = currentMenuIndex;
2472 }
2473
2474 Flickables.ListView {
2475 id: listViewContent
2476 objectName: "indicatorsContentListView"
2477- anchors {
2478- left: parent.left
2479- right: parent.right
2480- top: listViewHeader.bottom
2481- bottom: parent.bottom
2482- }
2483+ anchors.fill: parent
2484 model: content.indicatorsModel
2485- clip: true
2486
2487- currentIndex: listViewHeader.currentIndex
2488+ highlightFollowsCurrentItem: true
2489 interactive: false
2490 highlightMoveDuration: 0
2491 orientation: ListView.Horizontal
2492 // Load all the indicator menus (a big number)
2493 cacheBuffer: 1073741823
2494
2495+ // for additions/removals.
2496+ onCountChanged: {
2497+ listViewContent.currentIndex = content.currentMenuIndex;
2498+ }
2499+
2500 delegate: Loader {
2501 id: loader
2502+
2503 width: ListView.view.width
2504 height: ListView.view.height
2505 objectName: identifier
2506-
2507- source: pageSource
2508 asynchronous: true
2509+ visible: ListView.isCurrentItem
2510+
2511+ sourceComponent: IndicatorPage {
2512+ objectName: identifier + "-page"
2513+
2514+ identifier: model.identifier
2515+ busName: indicatorProperties.busName
2516+ actionsObjectPath: indicatorProperties.actionsObjectPath
2517+ menuObjectPath: indicatorProperties.menuObjectPath
2518+ }
2519
2520 onVisibleChanged: {
2521 // Reset the indicator states
2522- if (!visible && item && item["reset"]) {
2523- item.reset()
2524- }
2525- }
2526-
2527- onLoaded: {
2528- for(var pName in indicatorProperties) {
2529- if (item.hasOwnProperty(pName)) {
2530- item[pName] = indicatorProperties[pName]
2531- }
2532- }
2533- }
2534-
2535- Binding {
2536- target: loader.item
2537- property: "identifier"
2538- value: identifier
2539- }
2540-
2541- Binding {
2542- target: loader.item
2543- property: "objectName"
2544- value: identifier + "-page"
2545+ if (!visible && status == Loader.Ready) {
2546+ item.reset();
2547+ }
2548 }
2549 }
2550 }
2551
2552=== removed file 'qml/Panel/Panel.qml'
2553--- qml/Panel/Panel.qml 2014-07-10 13:36:41 +0000
2554+++ qml/Panel/Panel.qml 1970-01-01 00:00:00 +0000
2555@@ -1,191 +0,0 @@
2556-/*
2557- * Copyright (C) 2013 Canonical, Ltd.
2558- *
2559- * This program is free software; you can redistribute it and/or modify
2560- * it under the terms of the GNU General Public License as published by
2561- * the Free Software Foundation; version 3.
2562- *
2563- * This program is distributed in the hope that it will be useful,
2564- * but WITHOUT ANY WARRANTY; without even the implied warranty of
2565- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2566- * GNU General Public License for more details.
2567- *
2568- * You should have received a copy of the GNU General Public License
2569- * along with this program. If not, see <http://www.gnu.org/licenses/>.
2570- */
2571-
2572-import QtQuick 2.0
2573-import Ubuntu.Components 0.1
2574-import Unity.Application 0.1
2575-import "../Components"
2576-import "../Components/ListItems"
2577-
2578-Item {
2579- id: root
2580- readonly property real panelHeight: indicatorArea.y + d.indicatorHeight
2581- property alias indicators: __indicators
2582- property alias callHint: __callHint
2583- property bool fullscreenMode: false
2584-
2585- Rectangle {
2586- id: darkenedArea
2587- property real darkenedOpacity: 0.6
2588- anchors {
2589- top: parent.top
2590- topMargin: panelHeight
2591- left: parent.left
2592- right: parent.right
2593- bottom: parent.bottom
2594- }
2595- color: "black"
2596- opacity: indicators.unitProgress * darkenedOpacity
2597-
2598- MouseArea {
2599- anchors.fill: parent
2600- enabled: indicators.shown
2601- onClicked: if (indicators.fullyOpened) indicators.hide();
2602- }
2603- }
2604-
2605- Item {
2606- id: indicatorArea
2607- objectName: "indicatorArea"
2608-
2609- anchors.fill: parent
2610-
2611- Behavior on anchors.topMargin { StandardAnimation {} }
2612-
2613- BorderImage {
2614- id: dropShadow
2615- anchors {
2616- fill: indicators
2617- leftMargin: -units.gu(1)
2618- bottomMargin: -units.gu(1)
2619- }
2620- visible: indicators.height > indicators.panelHeight
2621- source: "graphics/rectangular_dropshadow.sci"
2622- }
2623-
2624- VerticalThinDivider {
2625- id: indicatorDividor
2626- anchors {
2627- top: indicators.top
2628- bottom: indicators.bottom
2629- right: indicators.left
2630-
2631- topMargin: indicatorArea.anchors.topMargin + indicators.panelHeight
2632- }
2633-
2634- width: units.dp(2)
2635- source: "graphics/VerticalDivider.png"
2636- }
2637-
2638- Rectangle {
2639- id: indicatorAreaBackground
2640- color: callHint.visible ? "green" : "black"
2641- anchors {
2642- top: parent.top
2643- left: parent.left
2644- right: parent.right
2645- }
2646- height: indicators.panelHeight
2647-
2648- Behavior on color { ColorAnimation { duration: UbuntuAnimation.FastDuration } }
2649- }
2650-
2651- PanelSeparatorLine {
2652- id: nonIndicatorAreaSeparatorLine
2653- anchors {
2654- top: indicatorAreaBackground.bottom
2655- left: parent.left
2656- right: indicators.left
2657- }
2658- saturation: 1 - indicators.unitProgress
2659- }
2660-
2661- MouseArea {
2662- anchors {
2663- top: parent.top
2664- left: parent.left
2665- right: indicators.left
2666- }
2667- height: indicators.panelHeight
2668- enabled: callHint.visible
2669- onClicked: callHint.showLiveCall()
2670- }
2671-
2672- Indicators {
2673- id: __indicators
2674- objectName: "indicators"
2675-
2676- anchors {
2677- top: parent.top
2678- right: parent.right
2679- }
2680-
2681- width: root.width
2682- shown: false
2683- panelHeight: units.gu(3)
2684- openedHeight: root.height
2685- overFlowWidth: {
2686- if (callHint.visible) {
2687- return Math.max(root.width - (callHint.width + units.gu(2)), 0)
2688- }
2689- return root.width
2690- }
2691-
2692- enableHint: !callHint.active && !fullscreenMode
2693- showHintBottomMargin: fullscreenMode ? -panelHeight : 0
2694-
2695- onShowTapped: {
2696- if (callHint.active) {
2697- callHint.showLiveCall();
2698- }
2699- }
2700- }
2701-
2702- ActiveCallHint {
2703- id: __callHint
2704- anchors {
2705- top: parent.top
2706- left: parent.left
2707- }
2708- height: indicators.panelHeight
2709- visible: active && indicators.state == "initial"
2710- }
2711-
2712- PanelSeparatorLine {
2713- id: indicatorsSeparatorLine
2714- visible: true
2715- anchors {
2716- top: indicators.bottom
2717- left: indicatorDividor.left
2718- right: indicators.right
2719- }
2720- }
2721- }
2722-
2723- QtObject {
2724- id: d
2725- readonly property real indicatorHeight: indicators.panelHeight + indicatorsSeparatorLine.height
2726- }
2727-
2728- states: [
2729- State {
2730- name: "onscreen" //fully opaque and visible at top edge of screen
2731- when: !fullscreenMode
2732- PropertyChanges {
2733- target: indicatorArea;
2734- anchors.topMargin: 0
2735- }
2736- },
2737- State {
2738- name: "offscreen" //pushed off screen
2739- when: fullscreenMode
2740- PropertyChanges {
2741- target: indicatorArea;
2742- anchors.topMargin: indicators.state === "initial" ? -d.indicatorHeight : 0
2743- }
2744- }
2745- ]
2746-}
2747
2748=== added file 'qml/Panel/PanelVelocityCalculator.qml'
2749--- qml/Panel/PanelVelocityCalculator.qml 1970-01-01 00:00:00 +0000
2750+++ qml/Panel/PanelVelocityCalculator.qml 2014-10-21 21:16:05 +0000
2751@@ -0,0 +1,54 @@
2752+/*
2753+ * Copyright (C) 2014 Canonical, Ltd.
2754+ *
2755+ * This program is free software; you can redistribute it and/or modify
2756+ * it under the terms of the GNU General Public License as published by
2757+ * the Free Software Foundation; version 3.
2758+ *
2759+ * This program is distributed in the hope that it will be useful,
2760+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2761+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2762+ * GNU General Public License for more details.
2763+ *
2764+ * You should have received a copy of the GNU General Public License
2765+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2766+ */
2767+
2768+import QtQuick 2.2
2769+import Ubuntu.Gestures 0.1
2770+
2771+Item {
2772+ id: root
2773+ property real trackedValue: 0
2774+ property bool velocityAboveThreshold: false
2775+ property real velocityThreshold: 0.4
2776+
2777+ function reset() {
2778+ velocityTimer.stop();
2779+ velocityAboveThreshold = false;
2780+ calc.reset();
2781+ }
2782+
2783+ function update() {
2784+ calc.trackedPosition = trackedValue;
2785+ velocityAboveThreshold = Math.abs(calc.calculate()) > velocityThreshold;
2786+
2787+ if (velocityAboveThreshold) { // only start timer if we're above the threshold.
2788+ velocityTimer.start();
2789+ } else {
2790+ velocityTimer.stop();
2791+ }
2792+ }
2793+
2794+ onTrackedValueChanged: update();
2795+
2796+ AxisVelocityCalculator {
2797+ id: calc
2798+ }
2799+
2800+ Timer {
2801+ id: velocityTimer
2802+ interval: 50
2803+ onTriggered: update();
2804+ }
2805+}
2806
2807=== modified file 'qml/Shell.qml'
2808--- qml/Shell.qml 2014-10-13 15:41:29 +0000
2809+++ qml/Shell.qml 2014-10-21 21:16:05 +0000
2810@@ -36,6 +36,7 @@
2811 import "Components"
2812 import "Notifications"
2813 import "Stages"
2814+import "Panel/Indicators"
2815 import Unity.Notifications 1.0 as NotificationBackend
2816 import Unity.Session 0.1
2817 import Unity.DashCommunicator 0.1
2818@@ -243,7 +244,7 @@
2819 target: applicationsDisplayLoader.item
2820 property: "maximizedAppTopMargin"
2821 // Not just using panel.panelHeight as that changes depending on the focused app.
2822- value: panel.indicators.panelHeight
2823+ value: panel.indicators.minimizedPanelHeight + units.dp(2) // dp(2) for orange line
2824 }
2825 Binding {
2826 target: applicationsDisplayLoader.item
2827@@ -646,7 +647,17 @@
2828 available: edgeDemo.panelEnabled && (!shell.locked || AccountsService.enableIndicatorsWhileLocked) && !greeter.hasLockedApp
2829 contentEnabled: edgeDemo.panelContentEnabled
2830 width: parent.width > units.gu(60) ? units.gu(40) : parent.width
2831- panelHeight: units.gu(3)
2832+
2833+ minimizedPanelHeight: units.gu(3)
2834+ expandedPanelHeight: units.gu(7)
2835+
2836+ indicatorsModel: visibleIndicators.model
2837+ }
2838+
2839+ VisibleIndicators {
2840+ id: visibleIndicators
2841+ // TODO: This should be sourced by device type (eg "desktop", "tablet", "phone"...)
2842+ Component.onCompleted: initialise(indicatorProfile)
2843 }
2844
2845 property bool topmostApplicationIsFullscreen:
2846@@ -709,9 +720,9 @@
2847 model: NotificationBackend.Model
2848 margin: units.gu(1)
2849
2850- y: panel.panelHeight
2851+ y: topmostIsFullscreen ? 0 : panel.panelHeight
2852 width: parent.width
2853- height: parent.height - panel.panelHeight
2854+ height: parent.height - (topmostIsFullscreen ? 0 : panel.panelHeight)
2855
2856 states: [
2857 State {
2858@@ -763,7 +774,7 @@
2859 paused: Powerd.status === Powerd.Off // Saves power
2860 greeter: greeter
2861 launcher: launcher
2862- indicators: panel.indicators
2863+ panel: panel
2864 stages: stages
2865 }
2866
2867
2868=== modified file 'tests/autopilot/unity8/indicators/tests/test_indicators.py'
2869--- tests/autopilot/unity8/indicators/tests/test_indicators.py 2014-10-09 13:57:46 +0000
2870+++ tests/autopilot/unity8/indicators/tests/test_indicators.py 2014-10-21 21:16:05 +0000
2871@@ -61,7 +61,7 @@
2872 self.skipTest('Nexus 10 does not have bluetooth at the moment.')
2873
2874 def test_indicator_exists(self):
2875- self.main_window._get_indicator_widget(
2876+ self.main_window._get_indicator_panel_item(
2877 self.indicator_name
2878 )
2879
2880
2881=== modified file 'tests/autopilot/unity8/shell/emulators/main_window.py'
2882--- tests/autopilot/unity8/shell/emulators/main_window.py 2014-08-12 17:30:05 +0000
2883+++ tests/autopilot/unity8/shell/emulators/main_window.py 2014-10-21 21:16:05 +0000
2884@@ -75,15 +75,15 @@
2885 def get_pinentryField(self):
2886 return self.select_single(objectName="pinentryField")
2887
2888- def _get_indicator_widget(self, indicator_name):
2889+ def _get_indicator_panel_item(self, indicator_name):
2890 return self.select_single(
2891- 'DefaultIndicatorWidget',
2892- objectName=indicator_name+'-widget'
2893+ 'IndicatorItem',
2894+ objectName=indicator_name+'-panelItem'
2895 )
2896
2897 def _get_indicator_page(self, indicator_name):
2898 return self.select_single(
2899- 'DefaultIndicatorPage',
2900+ 'IndicatorPage',
2901 objectName=indicator_name+'-page'
2902 )
2903
2904@@ -93,12 +93,12 @@
2905
2906 :returns: The indicator page.
2907 """
2908- widget = self._get_indicator_widget(indicator_name)
2909+ widget = self._get_indicator_panel_item(indicator_name)
2910 start_x, start_y = input.get_center_point(widget)
2911 end_x = start_x
2912 end_y = self.height
2913 self.pointing_device.drag(start_x, start_y, end_x, end_y)
2914- self.wait_select_single('Indicators', fullyOpened=True)
2915+ self.wait_select_single('IndicatorsMenu', fullyOpened=True)
2916 return self._get_indicator_page(indicator_name)
2917
2918 @autopilot_logging.log_action(logger.info)
2919
2920=== modified file 'tests/mocks/Unity/Indicators/Indicators.qmltypes'
2921--- tests/mocks/Unity/Indicators/Indicators.qmltypes 2014-10-21 21:16:04 +0000
2922+++ tests/mocks/Unity/Indicators/Indicators.qmltypes 2014-10-21 21:16:05 +0000
2923@@ -105,10 +105,8 @@
2924 values: {
2925 "Identifier": 0,
2926 "Position": 1,
2927- "WidgetSource": 2,
2928- "PageSource": 3,
2929- "IndicatorProperties": 4,
2930- "IsVisible": 5
2931+ "IndicatorProperties": 2,
2932+ "IsVisible": 3
2933 }
2934 }
2935 }
2936
2937=== modified file 'tests/mocks/Unity/Indicators/IndicatorsModel.qml'
2938--- tests/mocks/Unity/Indicators/IndicatorsModel.qml 2014-10-21 21:16:04 +0000
2939+++ tests/mocks/Unity/Indicators/IndicatorsModel.qml 2014-10-21 21:16:05 +0000
2940@@ -20,42 +20,97 @@
2941 Indicators.FakeIndicatorsModel {
2942 id: root
2943
2944- Component.onCompleted: {
2945- Indicators.UnityMenuModelCache.setCachedModelData("com.canonical.indicators.fake1",
2946- "/com/canonical/indicators/fake1",
2947- "/com/canonical/indicators/fake1",
2948+ property var originalModelData: [
2949+ {
2950+ "identifier": "fake-indicator-bluetooth",
2951+ "indicatorProperties": {
2952+ "enabled": true,
2953+ "busName": "com.canonical.indicators.fake1",
2954+ "menuObjectPath": "/com/canonical/indicators/fake1",
2955+ "actionsObjectPath": "/com/canonical/indicators/fake1"
2956+ }
2957+ },
2958+ {
2959+ "identifier": "fake-indicator-network",
2960+ "indicatorProperties": {
2961+ "enabled": true,
2962+ "busName": "com.canonical.indicators.fake2",
2963+ "menuObjectPath": "/com/canonical/indicators/fake2",
2964+ "actionsObjectPath": "/com/canonical/indicators/fake2"
2965+ }
2966+ },
2967+ {
2968+ "identifier": "fake-indicator-messages",
2969+ "indicatorProperties": {
2970+ "enabled": true,
2971+ "busName": "com.canonical.indicators.fake3",
2972+ "menuObjectPath": "/com/canonical/indicators/fake3",
2973+ "actionsObjectPath": "/com/canonical/indicators/fake3"
2974+ }
2975+ },
2976+ {
2977+ "identifier": "fake-indicator-sound",
2978+ "indicatorProperties": {
2979+ "enabled": true,
2980+ "busName": "com.canonical.indicators.fake4",
2981+ "menuObjectPath": "/com/canonical/indicators/fake4",
2982+ "actionsObjectPath": "/com/canonical/indicators/fake4"
2983+ }
2984+ },
2985+ {
2986+ "identifier": "fake-indicator-power",
2987+ "indicatorProperties": {
2988+ "enabled": true,
2989+ "busName": "com.canonical.indicators.fake5",
2990+ "menuObjectPath": "/com/canonical/indicators/fake5",
2991+ "actionsObjectPath": "/com/canonical/indicators/fake5"
2992+ }
2993+ },
2994+ {
2995+ "identifier": "fake-indicator-datetime",
2996+ "indicatorProperties": {
2997+ "enabled": true,
2998+ "busName": "com.canonical.indicators.fake6",
2999+ "menuObjectPath": "/com/canonical/indicators/fake6",
3000+ "actionsObjectPath": "/com/canonical/indicators/fake6"
3001+ }
3002+ }
3003+ ]
3004+
3005+ function load(profile) {
3006+ unload();
3007+ root.modelData = originalModelData;
3008+
3009+ Indicators.UnityMenuModelCache.setCachedModelData("/com/canonical/indicators/fake1",
3010 getUnityMenuModelData("fake-indicator-bluetooth",
3011 "Bluetooth (F)",
3012 "",
3013 [ "image://theme/bluetooth-active" ]));
3014- Indicators.UnityMenuModelCache.setCachedModelData("com.canonical.indicators.fake2",
3015- "/com/canonical/indicators/fake2",
3016- "/com/canonical/indicators/fake2",
3017+ Indicators.UnityMenuModelCache.setCachedModelData("/com/canonical/indicators/fake2",
3018 getUnityMenuModelData("fake-indicator-network",
3019 "Network (F)",
3020 "",
3021 [ "image://theme/simcard-error", "image://theme/wifi-high" ]));
3022- Indicators.UnityMenuModelCache.setCachedModelData("com.canonical.indicators.fake3",
3023- "/com/canonical/indicators/fake3",
3024- "/com/canonical/indicators/fake3",
3025- getUnityMenuModelData("fake-indicator-sound",
3026+ Indicators.UnityMenuModelCache.setCachedModelData("/com/canonical/indicators/fake3",
3027+ getUnityMenuModelData("fake-indicator-messages",
3028 "Messages (F)",
3029 "",
3030 [ "image://theme/messages-new" ]));
3031- Indicators.UnityMenuModelCache.setCachedModelData("com.canonical.indicators.fake4",
3032- "/com/canonical/indicators/fake4",
3033- "/com/canonical/indicators/fake4",
3034- getUnityMenuModelData("fake-indicator-power",
3035+ Indicators.UnityMenuModelCache.setCachedModelData("/com/canonical/indicators/fake4",
3036+ getUnityMenuModelData("fake-indicator-sound",
3037 "Sound (F)",
3038 "",
3039 [ "image://theme/audio-volume-high" ]));
3040- Indicators.UnityMenuModelCache.setCachedModelData("com.canonical.indicators.fake5",
3041- "/com/canonical/indicators/fake5",
3042- "/com/canonical/indicators/fake5",
3043+ Indicators.UnityMenuModelCache.setCachedModelData("/com/canonical/indicators/fake5",
3044 getUnityMenuModelData("fake-indicator-power",
3045 "Battery (F)",
3046 "",
3047 [ "image://theme/battery-020" ]));
3048+ Indicators.UnityMenuModelCache.setCachedModelData("/com/canonical/indicators/fake6",
3049+ getUnityMenuModelData("fake-indicator-datetime",
3050+ "Upcoming Events (F)",
3051+ "12:04",
3052+ []));
3053 }
3054
3055 function getUnityMenuModelData(identifier, title, label, icons) {
3056@@ -71,11 +126,12 @@
3057 "actionState": {
3058 "title": title,
3059 "label": label,
3060- "icons": icons
3061+ "icons": icons,
3062+ "visible": true
3063 },
3064 "isCheck": false,
3065 "isRadio": false,
3066- "isToggled": false,
3067+ "isToggled": false
3068 },
3069 "submenu": []
3070 }];
3071@@ -94,7 +150,7 @@
3072 "actionState": {},
3073 "isCheck": false,
3074 "isRadio": false,
3075- "isToggled": false,
3076+ "isToggled": false
3077 }};
3078 submenus.push(submenu);
3079 }
3080@@ -103,66 +159,20 @@
3081 return root;
3082 }
3083
3084- property var originalModelData: [
3085- {
3086- "identifier": "indicator-fake1",
3087- "widgetSource": "Indicators/DefaultIndicatorWidget.qml",
3088- "pageSource": "Indicators/DefaultIndicatorPage.qml",
3089- "indicatorProperties": {
3090- "enabled": true,
3091- "busName": "com.canonical.indicators.fake1",
3092- "menuObjectPath": "/com/canonical/indicators/fake1",
3093- "actionsObjectPath": "/com/canonical/indicators/fake1"
3094- }
3095- },
3096- {
3097- "identifier": "indicator-fake2",
3098- "widgetSource": "Indicators/DefaultIndicatorWidget.qml",
3099- "pageSource": "Indicators/DefaultIndicatorPage.qml",
3100- "indicatorProperties": {
3101- "enabled": true,
3102- "busName": "com.canonical.indicators.fake2",
3103- "menuObjectPath": "/com/canonical/indicators/fake2",
3104- "actionsObjectPath": "/com/canonical/indicators/fake2"
3105- }
3106- },
3107- {
3108- "identifier": "indicator-fake3",
3109- "widgetSource": "Indicators/DefaultIndicatorWidget.qml",
3110- "pageSource": "Indicators/DefaultIndicatorPage.qml",
3111- "indicatorProperties": {
3112- "enabled": true,
3113- "busName": "com.canonical.indicators.fake3",
3114- "menuObjectPath": "/com/canonical/indicators/fake3",
3115- "actionsObjectPath": "/com/canonical/indicators/fake3"
3116- }
3117- },
3118- {
3119- "identifier": "indicator-fake4",
3120- "widgetSource": "Indicators/DefaultIndicatorWidget.qml",
3121- "pageSource": "Indicators/DefaultIndicatorPage.qml",
3122- "indicatorProperties": {
3123- "enabled": true,
3124- "busName": "com.canonical.indicators.fake4",
3125- "menuObjectPath": "/com/canonical/indicators/fake4",
3126- "actionsObjectPath": "/com/canonical/indicators/fake4"
3127- }
3128- },
3129- {
3130- "identifier": "indicator-fake5",
3131- "widgetSource": "Indicators/DefaultIndicatorWidget.qml",
3132- "pageSource": "Indicators/DefaultIndicatorPage.qml",
3133- "indicatorProperties": {
3134- "enabled": true,
3135- "busName": "com.canonical.indicators.fake5",
3136- "menuObjectPath": "/com/canonical/indicators/fake5",
3137- "actionsObjectPath": "/com/canonical/indicators/fake5"
3138+ function setIndicatorVisible(identifier, visible) {
3139+ for (var i = 0; i < originalModelData.length; i++) {
3140+ if (originalModelData[i]["identifier"] === identifier) {
3141+ var data = Indicators.UnityMenuModelCache.getCachedModelData(
3142+ originalModelData[i]["indicatorProperties"]["menuObjectPath"]);
3143+
3144+ data[0]["rowData"]["actionState"]["visible"] = visible;
3145+
3146+ Indicators.UnityMenuModelCache.setCachedModelData(
3147+ originalModelData[i]["indicatorProperties"]["menuObjectPath"],
3148+ data);
3149+ break;
3150 }
3151 }
3152- ]
3153
3154- function load(profile) {
3155- unload();
3156- root.modelData = originalModelData;
3157 }
3158 }
3159
3160=== modified file 'tests/mocks/Unity/Indicators/RootActionState.qml'
3161--- tests/mocks/Unity/Indicators/RootActionState.qml 2014-10-21 21:16:04 +0000
3162+++ tests/mocks/Unity/Indicators/RootActionState.qml 2014-10-21 21:16:05 +0000
3163@@ -27,7 +27,7 @@
3164 property string rightLabel: cachedState && cachedState.hasOwnProperty("label") ? cachedState["label"] : ""
3165 property var icons: cachedState && cachedState.hasOwnProperty("icons") ? cachedState["icons"] : []
3166 property string accessibleName: cachedState && cachedState.hasOwnProperty("accessible-desc") ? cachedState["accessible-desc"] : ""
3167- visible: cachedState && cachedState.hasOwnProperty("visible") ? cachedState["visible"] : true
3168+ property bool indicatorVisible: cachedState && cachedState.hasOwnProperty("visible") ? cachedState["visible"] : true
3169
3170 property var cachedState: menu ? menu.get(0, "actionState") : undefined
3171 Connections {
3172@@ -45,5 +45,5 @@
3173 onRightLabelChanged: updated()
3174 onIconsChanged: updated()
3175 onAccessibleNameChanged: updated()
3176- onVisibleChanged: updated()
3177+ onIndicatorVisibleChanged: updated()
3178 }
3179
3180=== modified file 'tests/mocks/Unity/Indicators/fakeindicatorsmodel.cpp'
3181--- tests/mocks/Unity/Indicators/fakeindicatorsmodel.cpp 2014-10-21 21:16:04 +0000
3182+++ tests/mocks/Unity/Indicators/fakeindicatorsmodel.cpp 2014-10-21 21:16:05 +0000
3183@@ -110,8 +110,6 @@
3184 {
3185 roles[IndicatorsModelRole::Identifier] = "identifier";
3186 roles[IndicatorsModelRole::Position] = "position";
3187- roles[IndicatorsModelRole::WidgetSource] = "widgetSource";
3188- roles[IndicatorsModelRole::PageSource] = "pageSource";
3189 roles[IndicatorsModelRole::IndicatorProperties] = "indicatorProperties";
3190 }
3191 return roles;
3192
3193=== modified file 'tests/mocks/Unity/Indicators/fakeunitymenumodelcache.cpp'
3194--- tests/mocks/Unity/Indicators/fakeunitymenumodelcache.cpp 2014-10-21 21:16:04 +0000
3195+++ tests/mocks/Unity/Indicators/fakeunitymenumodelcache.cpp 2014-10-21 21:16:05 +0000
3196@@ -32,11 +32,9 @@
3197 {
3198 }
3199
3200-QSharedPointer<UnityMenuModel> FakeUnityMenuModelCache::model(const QByteArray& bus,
3201- const QByteArray& path,
3202- const QVariantMap& actions)
3203+QSharedPointer<UnityMenuModel> FakeUnityMenuModelCache::model(const QByteArray& path)
3204 {
3205- return UnityMenuModelCache::singleton()->model(bus, path, actions);
3206+ return UnityMenuModelCache::singleton()->model(path);
3207 }
3208
3209 bool FakeUnityMenuModelCache::contains(const QByteArray& path)
3210@@ -44,14 +42,18 @@
3211 return UnityMenuModelCache::singleton()->contains(path);
3212 }
3213
3214-void FakeUnityMenuModelCache::setCachedModelData(const QByteArray& bus,
3215- const QByteArray& path,
3216- const QVariantMap& actions,
3217+void FakeUnityMenuModelCache::setCachedModelData(const QByteArray& path,
3218 const QVariant& data)
3219 {
3220 // keep a ref forever!
3221 if (!m_models.contains(path)) {
3222- m_models[path] = model(bus, path, actions);
3223+ m_models[path] = model(path);
3224 }
3225 m_models[path]->setModelData(data);
3226 }
3227+
3228+QVariant FakeUnityMenuModelCache::getCachedModelData(const QByteArray& path)
3229+{
3230+ QSharedPointer<UnityMenuModel> model = this->model(path);
3231+ return model.isNull() ? QVariant() : model->modelData();
3232+}
3233
3234=== modified file 'tests/mocks/Unity/Indicators/fakeunitymenumodelcache.h'
3235--- tests/mocks/Unity/Indicators/fakeunitymenumodelcache.h 2014-10-21 21:16:04 +0000
3236+++ tests/mocks/Unity/Indicators/fakeunitymenumodelcache.h 2014-10-21 21:16:05 +0000
3237@@ -29,18 +29,14 @@
3238
3239 static FakeUnityMenuModelCache* singleton();
3240
3241- QSharedPointer<UnityMenuModel> model(const QByteArray& bus,
3242- const QByteArray& path,
3243- const QVariantMap& actions) override;
3244+ QSharedPointer<UnityMenuModel> model(const QByteArray& path) override;
3245 bool contains(const QByteArray& path) override;
3246
3247-
3248-
3249- Q_INVOKABLE void setCachedModelData(const QByteArray& bus,
3250- const QByteArray& path,
3251- const QVariantMap& actions,
3252+ Q_INVOKABLE void setCachedModelData(const QByteArray& path,
3253 const QVariant& data = QVariant());
3254
3255+ Q_INVOKABLE QVariant getCachedModelData(const QByteArray& path);
3256+
3257 private:
3258 static QPointer<FakeUnityMenuModelCache> theFakeCache;
3259 QHash<QByteArray, QSharedPointer<UnityMenuModel>> m_models;
3260
3261=== modified file 'tests/qmltests/CMakeLists.txt'
3262--- tests/qmltests/CMakeLists.txt 2014-10-21 21:16:04 +0000
3263+++ tests/qmltests/CMakeLists.txt 2014-10-21 21:16:05 +0000
3264@@ -12,7 +12,6 @@
3265 set(qmltest_DEFAULT_TARGETS qmlunittests)
3266 set(qmltest_DEFAULT_NO_ADD_TEST FALSE)
3267 set(qmltest_DEFAULT_PROPERTIES ENVIRONMENT "QT_QPA_PLATFORM=minimal")
3268-add_qml_test(Panel IndicatorItem)
3269 add_qml_test(utils/Unity/Test UnityTest)
3270
3271 set(qmltest_DEFAULT_TARGETS qmluitests)
3272@@ -72,13 +71,14 @@
3273 add_qml_test(Notifications Notifications)
3274 add_qml_test(Notifications VisualSnapDecisionsQueue)
3275 add_qml_test(Panel ActiveCallHint)
3276-add_qml_test(Panel IndicatorRow ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/QMenuModel")
3277-add_qml_test(Panel Indicators ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/QMenuModel")
3278+add_qml_test(Panel IndicatorItem)
3279+add_qml_test(Panel IndicatorItemRow ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/QMenuModel")
3280+add_qml_test(Panel IndicatorPage ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/QMenuModel")
3281+add_qml_test(Panel IndicatorsBar ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/QMenuModel")
3282+add_qml_test(Panel IndicatorsMenu ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/QMenuModel")
3283 add_qml_test(Panel MenuContent ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/QMenuModel")
3284 add_qml_test(Panel Panel ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/QMenuModel")
3285 add_qml_test(Panel SearchIndicator)
3286-add_qml_test(Panel/Indicators DefaultIndicatorWidget ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/QMenuModel")
3287-add_qml_test(Panel/Indicators DefaultIndicatorPage ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/QMenuModel")
3288 # These MenuItemFactory tests need the test/mocks/ to come before plugins/
3289 add_qml_test(Panel/Indicators MenuItemFactory IMPORT_PATHS ${CMAKE_BINARY_DIR}/tests/mocks ${qmltest_DEFAULT_IMPORT_PATHS})
3290 add_qml_test(Panel/Indicators MessageMenuItemFactory IMPORT_PATHS ${CMAKE_BINARY_DIR}/tests/mocks ${qmltest_DEFAULT_IMPORT_PATHS})
3291
3292=== modified file 'tests/qmltests/Greeter/tst_Clock.qml'
3293--- tests/qmltests/Greeter/tst_Clock.qml 2014-10-21 21:16:04 +0000
3294+++ tests/qmltests/Greeter/tst_Clock.qml 2014-10-21 21:16:05 +0000
3295@@ -37,9 +37,7 @@
3296 }
3297
3298 function updateDatetimeModelTime(label) {
3299- Indicators.UnityMenuModelCache.setCachedModelData("com.canonical.indicator.datetime",
3300- "/com/canonical/indicator/datetime/phone",
3301- "/com/canonical/indicator/datetime",
3302+ Indicators.UnityMenuModelCache.setCachedModelData("/com/canonical/indicator/datetime/phone",
3303 [{
3304 "rowData": {
3305 "actionState": { "label": label }
3306
3307=== added file 'tests/qmltests/Panel/IndicatorTest.qml'
3308--- tests/qmltests/Panel/IndicatorTest.qml 1970-01-01 00:00:00 +0000
3309+++ tests/qmltests/Panel/IndicatorTest.qml 2014-10-21 21:16:05 +0000
3310@@ -0,0 +1,80 @@
3311+/*
3312+ * Copyright 2014 Canonical Ltd.
3313+ *
3314+ * This program is free software; you can redistribute it and/or modify
3315+ * it under the terms of the GNU General Public License as published by
3316+ * the Free Software Foundation; version 3.
3317+ *
3318+ * This program is distributed in the hope that it will be useful,
3319+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3320+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3321+ * GNU General Public License for more details.
3322+ *
3323+ * You should have received a copy of the GNU General Public License
3324+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3325+ */
3326+
3327+import QtQuick 2.1
3328+import QtQuick.Layouts 1.1
3329+import QtTest 1.0
3330+import "../../../qml/Panel"
3331+import Ubuntu.Components 0.1
3332+import Unity.Test 0.1 as UT
3333+import Unity.Indicators 0.1 as Indicators
3334+
3335+Rectangle {
3336+ id: root
3337+ color: "white"
3338+
3339+ property alias indicatorsModel: __visibleIndicatorsModel
3340+ property alias originalModelData: __indicatorsModel.originalModelData
3341+
3342+ Indicators.VisibleIndicatorsModel {
3343+ id: __visibleIndicatorsModel
3344+
3345+ model: __indicatorsModel
3346+ }
3347+
3348+ Indicators.IndicatorsModel {
3349+ id: __indicatorsModel
3350+ Component.onCompleted: load();
3351+ }
3352+
3353+ function insertIndicator(index) {
3354+ var i;
3355+ var insertIndex = 0;
3356+ var done = false;
3357+ for (i = index; !done && i >= 1; i--) {
3358+
3359+ var lookFor = __indicatorsModel.originalModelData[i-1]["identifier"]
3360+
3361+ var j;
3362+ for (j = __indicatorsModel.modelData.length-1; !done && j >= 0; j--) {
3363+ if (__indicatorsModel.modelData[j]["identifier"] === lookFor) {
3364+ insertIndex = j+1;
3365+ done = true;
3366+ }
3367+ }
3368+ }
3369+ __indicatorsModel.insert(insertIndex, __indicatorsModel.originalModelData[index]);
3370+ }
3371+
3372+ function removeIndicator(index) {
3373+ var i;
3374+ for (i = 0; i < __indicatorsModel.modelData.length; i++) {
3375+ if (__indicatorsModel.modelData[i]["identifier"] === __indicatorsModel.originalModelData[index]["identifier"]) {
3376+ __indicatorsModel.remove(i);
3377+ break;
3378+ }
3379+ }
3380+ }
3381+
3382+ function setIndicatorVisible(index, visible) {
3383+ var identifier = __indicatorsModel.originalModelData[index]["identifier"];
3384+ __indicatorsModel.setIndicatorVisible(identifier, visible);
3385+ }
3386+
3387+ function resetData() {
3388+ __indicatorsModel.load();
3389+ }
3390+}
3391
3392=== removed file 'tests/qmltests/Panel/Indicators/tst_DefaultIndicatorWidget.qml'
3393--- tests/qmltests/Panel/Indicators/tst_DefaultIndicatorWidget.qml 2014-10-21 21:16:04 +0000
3394+++ tests/qmltests/Panel/Indicators/tst_DefaultIndicatorWidget.qml 1970-01-01 00:00:00 +0000
3395@@ -1,52 +0,0 @@
3396-/*
3397- * Copyright 2013 Canonical Ltd.
3398- *
3399- * This program is free software; you can redistribute it and/or modify
3400- * it under the terms of the GNU General Public License as published by
3401- * the Free Software Foundation; version 3.
3402- *
3403- * This program is distributed in the hope that it will be useful,
3404- * but WITHOUT ANY WARRANTY; without even the implied warranty of
3405- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3406- * GNU General Public License for more details.
3407- *
3408- * You should have received a copy of the GNU General Public License
3409- * along with this program. If not, see <http://www.gnu.org/licenses/>.
3410- */
3411-
3412-import QtQuick 2.0
3413-import QtTest 1.0
3414-import Unity.Test 0.1 as UT
3415-import QMenuModel 0.1
3416-import "../../../../qml/Panel/Indicators"
3417-
3418-Item {
3419- id: testView
3420- width: units.gu(40)
3421- height: units.gu(70)
3422-
3423- DefaultIndicatorWidget {
3424- id: widget
3425-
3426- anchors {
3427- left: parent.left
3428- top: parent.top
3429- }
3430-
3431- busName: "test"
3432- actionsObjectPath: "test"
3433- deviceMenuObjectPath: "test"
3434-
3435- rootMenuType: ""
3436-
3437- iconSize: units.gu(3.2)
3438- height: units.gu(3)
3439- }
3440-
3441- UT.UnityTestCase {
3442- name: "DefaultIndicatorWidget"
3443- when: windowShown
3444-
3445- // FIXME: add tests
3446- }
3447-}
3448
3449=== modified file 'tests/qmltests/Panel/tst_ActiveCallHint.qml'
3450--- tests/qmltests/Panel/tst_ActiveCallHint.qml 2014-09-11 14:53:35 +0000
3451+++ tests/qmltests/Panel/tst_ActiveCallHint.qml 2014-10-21 21:16:05 +0000
3452@@ -19,7 +19,6 @@
3453 import Unity.Test 0.1 as UT
3454 import Ubuntu.Telephony 0.1 as Telephony
3455 import Unity.Application 0.1
3456-import ".."
3457 import "../../../qml/Panel"
3458
3459 Item {
3460
3461=== added file 'tests/qmltests/Panel/tst_IndicatorItem.qml'
3462--- tests/qmltests/Panel/tst_IndicatorItem.qml 1970-01-01 00:00:00 +0000
3463+++ tests/qmltests/Panel/tst_IndicatorItem.qml 2014-10-21 21:16:05 +0000
3464@@ -0,0 +1,205 @@
3465+/*
3466+ * Copyright 2013-2014 Canonical Ltd.
3467+ *
3468+ * This program is free software; you can redistribute it and/or modify
3469+ * it under the terms of the GNU General Public License as published by
3470+ * the Free Software Foundation; version 3.
3471+ *
3472+ * This program is distributed in the hope that it will be useful,
3473+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3474+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3475+ * GNU General Public License for more details.
3476+ *
3477+ * You should have received a copy of the GNU General Public License
3478+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3479+ */
3480+
3481+import QtQuick 2.1
3482+import QtQuick.Layouts 1.1
3483+import QtTest 1.0
3484+import Ubuntu.Components 0.1
3485+import Unity.Test 0.1 as UT
3486+import "../../../qml/Panel"
3487+
3488+Rectangle {
3489+ width: units.gu(80)
3490+ height: units.gu(30)
3491+ color: "white"
3492+
3493+ RowLayout {
3494+ anchors.fill: parent
3495+ anchors.margins: units.gu(1)
3496+
3497+ Rectangle {
3498+ id: itemArea
3499+ color: "blue"
3500+ Layout.fillWidth: true
3501+ Layout.fillHeight: true
3502+
3503+ Rectangle {
3504+ color: "black"
3505+ anchors.fill: indicatorItem
3506+ }
3507+
3508+ IndicatorItem {
3509+ id: indicatorItem
3510+ height: expanded ? units.gu(7) : units.gu(3)
3511+ anchors.centerIn: parent
3512+ identifier: "indicator-test"
3513+
3514+ rootActionState {
3515+ title: titleLabel.text
3516+ leftLabel : leftLabel.text
3517+ rightLabel : rightLabel.text
3518+ icons : {
3519+ var icons = [];
3520+ var i = 0;
3521+ if (iconEnabled.checked) {
3522+ for (i = 0; i < String(iconCount.text); i++) {
3523+ icons.push("image://theme/audio-volume-high");
3524+ }
3525+ }
3526+ return icons;
3527+ }
3528+ }
3529+
3530+ Behavior on height {
3531+ NumberAnimation {
3532+ id: heightAnimation
3533+ duration: UbuntuAnimation.SnapDuration; easing: UbuntuAnimation.StandardEasing
3534+ }
3535+ }
3536+ }
3537+ }
3538+
3539+ ColumnLayout {
3540+ Layout.alignment: Qt.AlignTop
3541+ Layout.fillWidth: false
3542+
3543+ Button {
3544+ id: expandButton
3545+ Layout.fillWidth: true
3546+ text: indicatorItem.expanded ? "Collapse" : "Expand"
3547+ onClicked: indicatorItem.expanded = !indicatorItem.expanded
3548+ }
3549+
3550+ Button {
3551+ id: selectButton
3552+ Layout.fillWidth: true
3553+ text: indicatorItem.selected ? "Unselect" : "Select"
3554+ onClicked: indicatorItem.selected = !indicatorItem.selected
3555+ }
3556+
3557+ Rectangle {
3558+ Layout.preferredHeight: units.dp(1);
3559+ Layout.fillWidth: true;
3560+ color: "black"
3561+ }
3562+
3563+ RowLayout {
3564+ CheckBox { id: iconEnabled; checked: true }
3565+ Label { text: "icons Count:" }
3566+ TextField { id: iconCount; text: "1"; enabled: iconEnabled.checked }
3567+ }
3568+
3569+ RowLayout {
3570+ Label { text: "Left Label:" }
3571+ TextField { id: leftLabel; text: "Left"}
3572+ }
3573+
3574+ RowLayout {
3575+ Label { text: "Right Label:" }
3576+ TextField { id: rightLabel; text: "Right"}
3577+ }
3578+
3579+ RowLayout {
3580+ Label { text: "Title:" }
3581+ TextField { id: titleLabel; text: "Title"}
3582+ }
3583+ }
3584+ }
3585+
3586+ UT.UnityTestCase {
3587+ name: "IndicatorItem"
3588+ when: windowShown
3589+
3590+ function init() {
3591+ indicatorItem.selected = false;
3592+ indicatorItem.expanded = false;
3593+ indicatorItem.rootActionState.title = "Test Title";
3594+ indicatorItem.rootActionState.leftLabel = "TestLeftLabel";
3595+ indicatorItem.rootActionState.rightLabel = "TestRightLabel";
3596+ indicatorItem.rootActionState.icons = [ "image://theme/audio-volume-high" ];
3597+
3598+ tryCompare(heightAnimation, "running", false);
3599+ }
3600+
3601+ function test_expand() {
3602+ indicatorItem.expanded = true;
3603+ tryCompare(indicatorItem, "height", units.gu(7));
3604+ indicatorItem.expanded = false;
3605+ tryCompare(indicatorItem, "height", units.gu(3));
3606+ }
3607+
3608+ function test_minimizedVisibility() {
3609+ compare(findChild(indicatorItem, "leftLabel").opacity, 1.0);
3610+ compare(findChild(indicatorItem, "rightLabel").opacity, 1.0);
3611+ compare(findChild(indicatorItem, "icons").opacity, 1.0);
3612+ compare(findChild(indicatorItem, "indicatorName").opacity, 0.0);
3613+ }
3614+
3615+ function test_expandIcon() {
3616+ indicatorItem.expanded = true;
3617+
3618+ tryCompare(findChild(indicatorItem, "leftLabel"), "opacity", 0.0);
3619+ tryCompare(findChild(indicatorItem, "rightLabel"), "opacity", 0.0);
3620+ tryCompare(findChild(indicatorItem, "icons"), "opacity", 1.0);
3621+ tryCompare(findChild(indicatorItem, "indicatorName"), "opacity", 1.0);
3622+ }
3623+
3624+ function test_expandRightLabel() {
3625+ indicatorItem.expanded = true;
3626+
3627+ indicatorItem.rootActionState.icons = [];
3628+
3629+ tryCompare(findChild(indicatorItem, "leftLabel"), "opacity", 0.0);
3630+ tryCompare(findChild(indicatorItem, "rightLabel"), "opacity", 1.0);
3631+ tryCompare(findChild(indicatorItem, "icons"), "opacity", 0.0);
3632+ tryCompare(findChild(indicatorItem, "indicatorName"), "opacity", 1.0);
3633+ }
3634+
3635+ function test_expandLeftLabel() {
3636+ indicatorItem.expanded = true;
3637+
3638+ indicatorItem.rootActionState.rightLabel = "";
3639+ indicatorItem.rootActionState.icons = [];
3640+
3641+ tryCompare(findChild(indicatorItem, "rightLabel"), "opacity", 0.0);
3642+ tryCompare(findChild(indicatorItem, "leftLabel"), "opacity", 1.0);
3643+ tryCompare(findChild(indicatorItem, "icons"), "opacity", 0.0);
3644+ tryCompare(findChild(indicatorItem, "indicatorName"), "opacity", 1.0);
3645+ }
3646+
3647+ function test_select() {
3648+ tryCompare(findChild(indicatorItem, "icon0"), "color", "#ededed");
3649+ tryCompare(findChild(indicatorItem, "icon0"), "opacity", 1.0);
3650+ tryCompare(findChild(indicatorItem, "leftLabel"), "color", "#ededed");
3651+ tryCompare(findChild(indicatorItem, "rightLabel"), "color", "#ededed");
3652+ tryCompare(findChild(indicatorItem, "indicatorName"), "color", "#ededed");
3653+
3654+ indicatorItem.expanded = true;
3655+ tryCompare(findChild(indicatorItem, "icon0"), "color", "#4c4c4c");
3656+ tryCompare(findChild(indicatorItem, "icon0"), "opacity", 0.6);
3657+ tryCompare(findChild(indicatorItem, "leftLabel"), "color", "#4c4c4c");
3658+ tryCompare(findChild(indicatorItem, "rightLabel"), "color", "#4c4c4c");
3659+ tryCompare(findChild(indicatorItem, "indicatorName"), "color", "#4c4c4c");
3660+
3661+ indicatorItem.selected = true;
3662+ tryCompare(findChild(indicatorItem, "icon0"), "color", "#ededed");
3663+ tryCompare(findChild(indicatorItem, "icon0"), "opacity", 1.0);
3664+ tryCompare(findChild(indicatorItem, "leftLabel"), "color", "#ededed");
3665+ tryCompare(findChild(indicatorItem, "rightLabel"), "color", "#ededed");
3666+ tryCompare(findChild(indicatorItem, "indicatorName"), "color", "#ededed");
3667+ }
3668+ }
3669+}
3670
3671=== removed file 'tests/qmltests/Panel/tst_IndicatorItem.qml'
3672--- tests/qmltests/Panel/tst_IndicatorItem.qml 2014-10-21 21:16:04 +0000
3673+++ tests/qmltests/Panel/tst_IndicatorItem.qml 1970-01-01 00:00:00 +0000
3674@@ -1,50 +0,0 @@
3675-/*
3676- * Copyright 2013 Canonical Ltd.
3677- *
3678- * This program is free software; you can redistribute it and/or modify
3679- * it under the terms of the GNU General Public License as published by
3680- * the Free Software Foundation; version 3.
3681- *
3682- * This program is distributed in the hope that it will be useful,
3683- * but WITHOUT ANY WARRANTY; without even the implied warranty of
3684- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3685- * GNU General Public License for more details.
3686- *
3687- * You should have received a copy of the GNU General Public License
3688- * along with this program. If not, see <http://www.gnu.org/licenses/>.
3689- */
3690-
3691-import QtQuick 2.0
3692-import QtTest 1.0
3693-import ".."
3694-import "../../../qml/Panel"
3695-import Ubuntu.Components 0.1
3696-import Unity.Test 0.1 as UT
3697-
3698-Rectangle {
3699- width: units.gu(10)
3700- height: units.gu(5)
3701- color: "black"
3702-
3703- IndicatorItem {
3704- id: indicatorItem
3705- anchors.fill: parent
3706- }
3707-
3708- UT.UnityTestCase {
3709- name: "IndicatorItem"
3710-
3711- function test_dimmed() {
3712- indicatorItem.dimmed = false;
3713- tryCompareFunction(function(){return indicatorItem.opacity}, 1.0);
3714- indicatorItem.dimmed = true;
3715- tryCompareFunction(function(){return indicatorItem.opacity < 1.0}, true);
3716- }
3717-
3718- function test_empty() {
3719- compare(indicatorItem.indicatorVisible, false, "IndicatorItem should not be visible.");
3720- indicatorItem.widgetSource = "../../../qml/Panel/Indicators/DefaultIndicatorWidget.qml";
3721- tryCompare(indicatorItem, "indicatorVisible", true);
3722- }
3723- }
3724-}
3725
3726=== added file 'tests/qmltests/Panel/tst_IndicatorItemRow.qml'
3727--- tests/qmltests/Panel/tst_IndicatorItemRow.qml 1970-01-01 00:00:00 +0000
3728+++ tests/qmltests/Panel/tst_IndicatorItemRow.qml 2014-10-21 21:16:05 +0000
3729@@ -0,0 +1,290 @@
3730+/*
3731+ * Copyright 2013-2014 Canonical Ltd.
3732+ *
3733+ * This program is free software; you can redistribute it and/or modify
3734+ * it under the terms of the GNU General Public License as published by
3735+ * the Free Software Foundation; version 3.
3736+ *
3737+ * This program is distributed in the hope that it will be useful,
3738+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3739+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3740+ * GNU General Public License for more details.
3741+ *
3742+ * You should have received a copy of the GNU General Public License
3743+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3744+ */
3745+
3746+import QtQuick 2.1
3747+import QtQuick.Layouts 1.1
3748+import QtTest 1.0
3749+import "../../../qml/Panel"
3750+import Ubuntu.Components 0.1
3751+import Unity.Test 0.1 as UT
3752+import Unity.Indicators 0.1 as Indicators
3753+
3754+IndicatorTest {
3755+ id: root
3756+ width: units.gu(120)
3757+ height: units.gu(40)
3758+ color: "white"
3759+
3760+ RowLayout {
3761+ anchors.fill: parent
3762+ anchors.margins: units.gu(1)
3763+
3764+ Rectangle {
3765+ Layout.fillWidth: true
3766+ Layout.fillHeight: true
3767+
3768+ id: itemArea
3769+ color: "blue"
3770+
3771+ Rectangle {
3772+ color: "black"
3773+ anchors.fill: indicatorsRow
3774+ }
3775+
3776+ IndicatorItemRow {
3777+ id: indicatorsRow
3778+ height: expanded ? units.gu(7) : units.gu(3)
3779+ anchors.centerIn: parent
3780+ indicatorsModel: root.indicatorsModel
3781+ enableLateralChanges: ma.pressed
3782+
3783+ Behavior on height {
3784+ NumberAnimation {
3785+ id: heightAnimation
3786+ duration: UbuntuAnimation.SnapDuration; easing: UbuntuAnimation.StandardEasing
3787+ }
3788+ }
3789+
3790+ MouseArea {
3791+ id: ma
3792+ anchors.fill: parent
3793+ onPositionChanged: {
3794+ indicatorsRow.lateralPosition = mouse.x;
3795+ }
3796+ onPressed: {
3797+ if (pressed) {
3798+ indicatorsRow.lateralPosition = mouse.x;
3799+ indicatorsRow.selectItemAt(mouse.x);
3800+ }
3801+ }
3802+ }
3803+ }
3804+ }
3805+
3806+ ColumnLayout {
3807+ Layout.alignment: Qt.AlignTop
3808+ Layout.fillWidth: false
3809+
3810+ Button {
3811+ Layout.fillWidth: true
3812+ text: indicatorsRow.expanded ? "Collapse" : "Expand"
3813+ onClicked: indicatorsRow.expanded = !indicatorsRow.expanded
3814+ }
3815+
3816+ Rectangle {
3817+ Layout.preferredHeight: units.dp(1);
3818+ Layout.fillWidth: true;
3819+ color: "black"
3820+ }
3821+
3822+ Repeater {
3823+ model: root.originalModelData
3824+ RowLayout {
3825+ CheckBox {
3826+ checked: true
3827+ onCheckedChanged: checked ? insertIndicator(index) : removeIndicator(index);
3828+ }
3829+ Label {
3830+ Layout.fillWidth: true
3831+ text: modelData["identifier"]
3832+ }
3833+
3834+ CheckBox {
3835+ checked: true
3836+ onCheckedChanged: setIndicatorVisible(index, checked);
3837+ }
3838+ Label {
3839+ text: "visible"
3840+ }
3841+ }
3842+ }
3843+ }
3844+ }
3845+
3846+ UT.UnityTestCase {
3847+ name: "IndicatorItemRow"
3848+ when: windowShown
3849+
3850+ function init() {
3851+ root.resetData();
3852+
3853+ indicatorsRow.resetCurrentItem();
3854+ indicatorsRow.lateralPosition = -1;
3855+
3856+ indicatorsRow.expanded = false;
3857+ tryCompare(heightAnimation, "running", false);
3858+ tryCompare(findChild(indicatorsRow, "highlight"), "highlightCenterOffset", 0);
3859+ wait(1); // row seems to take a bit of time for item x values to update.
3860+ }
3861+
3862+ function wait_for_expansion_to_settle() {
3863+ tryCompare(heightAnimation, "running", false);
3864+ wait(200); // put a little extra wait in for things to settle
3865+ }
3866+
3867+ function test_indicatorRowChanges_data() {
3868+ return [
3869+ { remove: [0, 2] },
3870+ { remove: [0, 1, 2, 3, 4] },
3871+ ];
3872+ }
3873+
3874+ // test the changes in the available indicators updates the
3875+ // indicators that are visible.
3876+ function test_indicatorRowChanges(data) {
3877+ var i;
3878+ var item;
3879+ var itemsToRemove = [0, 2];
3880+
3881+ verify(root.originalModelData.length > 0);
3882+ for (i = 0; i < root.originalModelData.length; i++) {
3883+ item = findChild(indicatorsRow, root.originalModelData[i]["identifier"] + "-panelItem");
3884+ verify(item);
3885+
3886+ compare(item.ownIndex, i, "Item at incorrect index");
3887+ }
3888+
3889+ for (i = data.remove.length-1; i >= 0; i--) {
3890+ removeIndicator(data.remove[i]);
3891+ }
3892+
3893+ // test removals
3894+ for (i = 0; i < root.originalModelData.length; i++) {
3895+ item = findChild(indicatorsRow, root.originalModelData[i]["identifier"] + "-panelItem");
3896+
3897+ verify(data.remove.indexOf(i) !== -1 ? (item === null) : (item !== null));
3898+ }
3899+
3900+ // test insertion
3901+ for (i = 0; i < data.remove.length; i++) {
3902+ insertIndicator(data.remove[i]);
3903+ }
3904+
3905+ for (i = 0; i < root.originalModelData.length; i++) {
3906+ item = findChild(indicatorsRow, root.originalModelData[i]["identifier"] + "-panelItem");
3907+ verify(item);
3908+
3909+ compare(item.ownIndex, i, "Item at incorrect index");
3910+ }
3911+ }
3912+
3913+ function test_validCurrentItem_data() {
3914+ return [
3915+ { index: 0 },
3916+ { index: 2 },
3917+ { index: 4 }
3918+ ];
3919+ }
3920+
3921+ // test selecting the item at it's position sets the current item of the row.
3922+ function test_validCurrentItem(data) {
3923+ var dataItem = findChild(indicatorsRow, root.originalModelData[data.index]["identifier"] + "-panelItem");
3924+ verify(dataItem !== null);
3925+
3926+ indicatorsRow.selectItemAt(dataItem.x + dataItem.width/2);
3927+ compare(indicatorsRow.currentItem, dataItem);
3928+ }
3929+
3930+ // tests item default selection (no item at position X)
3931+ function test_invalidCurrentItem() {
3932+ indicatorsRow.selectItemAt(-100);
3933+ var item = findChild(indicatorsRow, root.originalModelData[0]["identifier"] + "-panelItem");
3934+ compare(indicatorsRow.currentItem, item);
3935+ }
3936+
3937+ // testing that changing the lateral position offset of the row changes the current item.
3938+ function test_lateralPositionChangesCurrentItem_data() {
3939+ return [
3940+ { tag: "0 -> 4", from: 0, to: 4 },
3941+ { tag: "3 -> 1", from: 3, to: 1 }
3942+ ];
3943+ }
3944+
3945+ function test_lateralPositionChangesCurrentItem(data) {
3946+ indicatorsRow.expanded = true;
3947+ wait_for_expansion_to_settle();
3948+
3949+ var fromItem = findChild(indicatorsRow, root.originalModelData[data.from]["identifier"] + "-panelItem");
3950+ verify(fromItem !== null);
3951+
3952+ var toItem = findChild(indicatorsRow, root.originalModelData[data.to]["identifier"] + "-panelItem");
3953+ verify(toItem !== null);
3954+
3955+ var fromPosition = indicatorsRow.mapFromItem(fromItem, fromItem.width/2, fromItem.height/2);
3956+ var toPosition = indicatorsRow.mapFromItem(toItem, toItem.width/2, toItem.height/2);
3957+
3958+ mousePress(indicatorsRow, fromPosition.x, fromPosition.y);
3959+ compare(indicatorsRow.currentItem, fromItem, "Initial item not selected");
3960+
3961+ // this uses the MouseArea above to change the indicatorRow lateralPosition
3962+ mouseFlick(indicatorsRow, fromPosition.x, fromPosition.y, toPosition.x, toPosition.y, false, false, units.gu(5), 30);
3963+
3964+ mouseRelease(indicatorsRow, fromPosition.x, fromPosition.y);
3965+ compare(indicatorsRow.currentItem, toItem, "Current item did not change to expected item");
3966+ }
3967+
3968+ // testing that positive changes to the lateral position offset shifts the highlight offset to the right
3969+ function test_positiveLateralPositionChangesHighlightOffset() {
3970+ indicatorsRow.expanded = true;
3971+ wait_for_expansion_to_settle();
3972+
3973+ var highlight = findChild(indicatorsRow, "highlight");
3974+ var item = findChild(indicatorsRow, root.originalModelData[2]["identifier"] + "-panelItem");
3975+ verify(item !== null);
3976+ var mappedPosition = indicatorsRow.mapFromItem(item, item.width/2, item.height/2);
3977+
3978+ mousePress(indicatorsRow, mappedPosition.x, mappedPosition.y);
3979+ var originalHightlightX = highlight.x;
3980+ var offset = 1;
3981+ while((highlight.x - originalHightlightX) <= units.gu(0.5) && offset < units.gu(10)) {
3982+ mouseMove(indicatorsRow, mappedPosition.x + offset, mappedPosition.y, 10);
3983+ offset = offset + 2;
3984+ }
3985+ // verify that we hit the offset
3986+ verify((highlight.x - originalHightlightX) >= units.gu(0.5));
3987+ mouseRelease(indicatorsRow);
3988+
3989+ // should go back to 0
3990+ tryCompare(highlight, "highlightCenterOffset", 0);
3991+ }
3992+
3993+ // testing that negative changes to the lateral position offset shifts the highlight offset to the left
3994+ function test_negativeLateralPositionChangesHighlightOffset() {
3995+ indicatorsRow.expanded = true;
3996+ wait_for_expansion_to_settle();
3997+
3998+ var highlight = findChild(indicatorsRow, "highlight");
3999+ var item = findChild(indicatorsRow, root.originalModelData[2]["identifier"] + "-panelItem");
4000+ verify(item !== null);
4001+ var mappedPosition = indicatorsRow.mapFromItem(item, item.width/2, item.height/2);
4002+
4003+ mousePress(indicatorsRow, mappedPosition.x, mappedPosition.y);
4004+ var originalHightlightX = highlight.x;
4005+ var offset = 1;
4006+ while((highlight.x - originalHightlightX) >= -units.gu(0.5) && offset < units.gu(10)) {
4007+ mouseMove(indicatorsRow, mappedPosition.x - offset, mappedPosition.y, 10);
4008+ offset = offset + 2;
4009+ }
4010+
4011+ // verify that we hit the offset
4012+ verify((highlight.x - originalHightlightX) <= -units.gu(0.5));
4013+ mouseRelease(indicatorsRow);
4014+
4015+ // should go back to 0
4016+ tryCompare(findChild(indicatorsRow, "highlight"), "highlightCenterOffset", 0);
4017+ }
4018+ }
4019+}
4020
4021=== renamed file 'tests/qmltests/Panel/Indicators/tst_DefaultIndicatorPage.qml' => 'tests/qmltests/Panel/tst_IndicatorPage.qml'
4022--- tests/qmltests/Panel/Indicators/tst_DefaultIndicatorPage.qml 2014-10-21 21:16:04 +0000
4023+++ tests/qmltests/Panel/tst_IndicatorPage.qml 2014-10-21 21:16:05 +0000
4024@@ -1,5 +1,5 @@
4025 /*
4026- * Copyright 2013 Canonical Ltd.
4027+ * Copyright 2013-2014 Canonical Ltd.
4028 *
4029 * This program is free software; you can redistribute it and/or modify
4030 * it under the terms of the GNU General Public License as published by
4031@@ -18,14 +18,14 @@
4032 import QtTest 1.0
4033 import Unity.Test 0.1 as UT
4034 import Unity.Indicators 0.1 as Indicators
4035-import "../../../../qml/Panel/Indicators"
4036+import "../../../qml/Panel"
4037
4038 Item {
4039 id: testView
4040 width: units.gu(40)
4041 height: units.gu(70)
4042
4043- DefaultIndicatorPage {
4044+ IndicatorPage {
4045 id: page
4046 anchors.fill: parent
4047
4048@@ -110,14 +110,12 @@
4049 }]; // end row 1
4050
4051 function initializeMenuData(data) {
4052- Indicators.UnityMenuModelCache.setCachedModelData("com.canonical.indicator.test",
4053- "/com/canonical/indicator/test",
4054- "/com/canonical/indicator/test",
4055+ Indicators.UnityMenuModelCache.setCachedModelData("/com/canonical/indicator/test",
4056 data);
4057 }
4058
4059 UT.UnityTestCase {
4060- name: "DefaultIndicatorPage"
4061+ name: "IndicatorPage"
4062
4063 function init() {
4064 initializeMenuData([]);
4065
4066=== removed file 'tests/qmltests/Panel/tst_IndicatorRow.qml'
4067--- tests/qmltests/Panel/tst_IndicatorRow.qml 2014-10-21 21:16:04 +0000
4068+++ tests/qmltests/Panel/tst_IndicatorRow.qml 1970-01-01 00:00:00 +0000
4069@@ -1,158 +0,0 @@
4070-/*
4071- * Copyright 2013 Canonical Ltd.
4072- *
4073- * This program is free software; you can redistribute it and/or modify
4074- * it under the terms of the GNU General Public License as published by
4075- * the Free Software Foundation; version 3.
4076- *
4077- * This program is distributed in the hope that it will be useful,
4078- * but WITHOUT ANY WARRANTY; without even the implied warranty of
4079- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4080- * GNU General Public License for more details.
4081- *
4082- * You should have received a copy of the GNU General Public License
4083- * along with this program. If not, see <http://www.gnu.org/licenses/>.
4084- */
4085-
4086-import QtQuick 2.0
4087-import QtTest 1.0
4088-import Unity.Test 0.1 as UT
4089-import ".."
4090-import "../../../qml/Panel"
4091-import Unity.Indicators 0.1 as Indicators
4092-
4093-/*
4094- This tests the IndicatorRow component by using a fake model to stage data in the indicators
4095- A view will show with indicators at the top, as does in the shell.
4096-*/
4097-Item {
4098- id: rootItem
4099- width: units.gu(40)
4100- height: units.gu(60)
4101-
4102- PanelBackground {
4103- anchors.fill: indicatorRow
4104- }
4105-
4106- IndicatorRow {
4107- id: indicatorRow
4108- anchors {
4109- left: parent.left
4110- right: parent.right
4111- }
4112-
4113- indicatorsModel: indicatorModel
4114-
4115- Component.onCompleted: indicatorModel.load("test1")
4116- }
4117-
4118- Indicators.IndicatorsModel {
4119- id: indicatorModel
4120- }
4121-
4122- UT.UnityTestCase {
4123- name: "IndicatorRow"
4124- when: windowShown
4125-
4126- function init() {
4127- indicatorModel.load("test1");
4128-
4129- indicatorRow.state = "initial";
4130- indicatorRow.setCurrentItemIndex(-1);
4131- indicatorRow.unitProgress = 0.0;
4132- }
4133-
4134- function get_indicator_item(index) {
4135- return findChild(indicatorRow.row, "item" + index);
4136- }
4137-
4138- function test_set_current_item() {
4139- indicatorRow.setCurrentItemIndex(0);
4140- compare(indicatorRow.indicatorsModel.data(indicatorRow.currentItemIndex, Indicators.IndicatorsModelRole.Identifier),
4141- "indicator-fake1",
4142- "Incorrect item at position 0");
4143-
4144- indicatorRow.setCurrentItemIndex(1);
4145- compare(indicatorRow.indicatorsModel.data(indicatorRow.currentItemIndex, Indicators.IndicatorsModelRole.Identifier),
4146- "indicator-fake2",
4147- "Incorrect item at position 1");
4148-
4149- indicatorRow.setCurrentItemIndex(2);
4150- compare(indicatorRow.indicatorsModel.data(indicatorRow.currentItemIndex, Indicators.IndicatorsModelRole.Identifier),
4151- "indicator-fake3",
4152- "Incorrect item at position 2");
4153- }
4154-
4155- function test_highlight_data() {
4156- return [
4157- { index: 0, progress: 0.0, current: false, other: false },
4158- { index: 0, progress: 0.1, current: true, other: false },
4159- { index: 0, progress: 0.5, current: true, other: false },
4160- { index: 0, progress: 1.0, current: true, other: false },
4161- { index: 2, progress: 0.0, current: false, other: false },
4162- { index: 2, progress: 0.1, current: true, other: false },
4163- { index: 2, progress: 0.5, current: true, other: false },
4164- { index: 2, progress: 1.0, current: true, other: false }
4165- ];
4166- }
4167-
4168- function test_highlight(data) {
4169- indicatorRow.unitProgress = data.progress;
4170- indicatorRow.setCurrentItemIndex(data.index);
4171-
4172- compare(indicatorRow.currentItem.highlighted, data.current, "Indicator hightlight did not match for current item");
4173-
4174- for (var i = 0; i < indicatorRow.row.count; i++) {
4175- compare(get_indicator_item(i).highlighted, i === data.index ? data.current: data.other, "Indicator hightlight did not match for item iter");
4176- }
4177- }
4178-
4179- function test_opacity_data() {
4180- return [
4181- { index: 0, progress: 0.0, current: 1.0, other: 1.0 },
4182- { index: 0, progress: 0.1, current: 1.0, other: 0.9 },
4183- { index: 0, progress: 0.5, current: 1.0, other: 0.5 },
4184- { index: 0, progress: 1.0, current: 1.0, other: 0.0 },
4185- { index: 2, progress: 0.0, current: 1.0, other: 1.0 },
4186- { index: 2, progress: 0.1, current: 1.0, other: 0.9 },
4187- { index: 2, progress: 0.5, current: 1.0, other: 0.5 },
4188- { index: 2, progress: 1.0, current: 1.0, other: 0.0 }
4189- ];
4190- }
4191-
4192- function test_opacity(data) {
4193- indicatorRow.unitProgress = data.progress;
4194- indicatorRow.setCurrentItemIndex(data.index);
4195-
4196- tryCompare(indicatorRow.currentItem, "opacity", data.current);
4197-
4198- for (var i = 0; i < indicatorRow.row.count; i++) {
4199- tryCompare(get_indicator_item(i), "opacity", i === data.index ? data.current: data.other);
4200- }
4201- }
4202-
4203- function test_dimmed_data() {
4204- return [
4205- { index: 0, progress: 0.0, current: false, other: false },
4206- { index: 0, progress: 0.1, current: false, other: true },
4207- { index: 0, progress: 0.5, current: false, other: true },
4208- { index: 0, progress: 1.0, current: false, other: true },
4209- { index: 2, progress: 0.0, current: false, other: false },
4210- { index: 2, progress: 0.1, current: false, other: true },
4211- { index: 2, progress: 0.5, current: false, other: true },
4212- { index: 2, progress: 1.0, current: false, other: true }
4213- ];
4214- }
4215-
4216- function test_dimmed(data) {
4217- indicatorRow.unitProgress = data.progress;
4218- indicatorRow.setCurrentItemIndex(data.index);
4219-
4220- compare(indicatorRow.currentItem.dimmed, data.current, "Indicator dim did not match for current item");
4221-
4222- for (var i = 0; i < indicatorRow.row.count; i++) {
4223- compare(get_indicator_item(i).dimmed, i === data.index ? data.current: data.other, "Indicator dim did not match for item iter");
4224- }
4225- }
4226- }
4227-}
4228
4229=== removed file 'tests/qmltests/Panel/tst_Indicators.qml'
4230--- tests/qmltests/Panel/tst_Indicators.qml 2014-10-21 21:16:04 +0000
4231+++ tests/qmltests/Panel/tst_Indicators.qml 1970-01-01 00:00:00 +0000
4232@@ -1,231 +0,0 @@
4233-/*
4234- * Copyright 2013 Canonical Ltd.
4235- *
4236- * This program is free software; you can redistribute it and/or modify
4237- * it under the terms of the GNU General Public License as published by
4238- * the Free Software Foundation; version 3.
4239- *
4240- * This program is distributed in the hope that it will be useful,
4241- * but WITHOUT ANY WARRANTY; without even the implied warranty of
4242- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4243- * GNU General Public License for more details.
4244- *
4245- * You should have received a copy of the GNU General Public License
4246- * along with this program. If not, see <http://www.gnu.org/licenses/>.
4247- */
4248-
4249-import QtQuick 2.0
4250-import QtTest 1.0
4251-import Unity.Test 0.1 as UT
4252-import Ubuntu.Components 0.1 as UC
4253-import ".."
4254-import "../../../qml/Panel"
4255-import "../../../qml/Components"
4256-
4257-/*
4258- This tests the Indicators component by using a fake model to stage data in the indicators
4259- A view will show with indicators at the top, as does in the shell. There is a clickable area
4260- marked "Click Me" which can be used to expose the indicators.
4261-*/
4262-Item {
4263- id: shell
4264- width: units.gu(40)
4265- height: units.gu(80)
4266-
4267- PanelBackground {
4268- anchors.fill: indicators
4269- }
4270-
4271- Indicators {
4272- id: indicators
4273- anchors {
4274- right: parent.right
4275- }
4276- width: (shell.width > units.gu(60)) ? units.gu(40) : shell.width
4277- y: 0
4278- shown: false
4279- profile: "test1"
4280-
4281- openedHeight: parent.height - button.height
4282- }
4283-
4284- UC.Button {
4285- id: button
4286- text: indicators.shown ? "Hide" : "Show"
4287- anchors {
4288- bottom: shell.bottom
4289- left: parent.left
4290- right: parent.right
4291- }
4292- height: 50
4293-
4294- onClicked: {
4295- if (!indicators.shown) {
4296- indicators.show();
4297- } else {
4298- indicators.hide();
4299- }
4300- }
4301- }
4302-
4303- UT.UnityTestCase {
4304- name: "Indicators"
4305- when: windowShown
4306-
4307- function init() {
4308- indicators.initialise();
4309-
4310- indicators.hide();
4311- tryCompare(indicators.hideAnimation, "running", false);
4312- tryCompare(indicators, "state", "initial");
4313- }
4314-
4315- // Showing the indicators should fully open the indicator panel.
4316- function test_show() {
4317- indicators.show()
4318- tryCompare(indicators, "fullyOpened", true);
4319- }
4320-
4321- // Test the change in the revealer lateral position changes the current panel menu to fit the position
4322- // of the indicator in the row.
4323- function test_change_revealer_lateral_position()
4324- {
4325- // tests changing the lateral position of the revealer activates the correct indicator items.
4326-
4327- var indicatorRow = findChild(indicators, "indicatorRow")
4328- verify(indicatorRow !== null);
4329- var indicatorRowItems = findChild(indicatorRow, "indicatorRowItems");
4330- verify(indicatorRowItems !== null);
4331-
4332- for (var i = 0; i < indicatorRowItems.count; i++) {
4333- var indicatorItem = findChild(indicatorRowItems, "item" + i);
4334-
4335- if (!indicatorItem.visible)
4336- continue;
4337-
4338- var indicatorPosition = indicators.mapFromItem(indicatorItem,
4339- indicatorItem.width/2, indicatorItem.height/2);
4340-
4341- touchFlick(indicators,
4342- indicatorPosition.x, indicatorPosition.y,
4343- indicatorPosition.x, indicators.openedHeight * 0.4,
4344- true /* beginTouch */, false /* endTouch */);
4345-
4346- compare(indicatorRow.currentItem, indicatorItem,
4347- "Incorrect item activated at position " + i);
4348-
4349- touchFlick(indicators,
4350- indicatorPosition.x, indicators.openedHeight * 0.4,
4351- indicatorPosition.x, indicatorPosition.y,
4352- false /* beginTouch */, true /* endTouch */);
4353-
4354- // wait until fully closed
4355- tryCompare(indicators, "height", indicators.panelHeight);
4356- }
4357- }
4358-
4359- // values for specific state changes are subject to internal decisions, so we can't
4360- // determine the true height value which would cause the state to change without making
4361- // too many assuptyions
4362- // However, we can assume that a partially opened panel will not be initial, and fully
4363- // opened panel will be locked.
4364-
4365- function test_progress_changes_state_to_not_initial() {
4366- indicators.height = indicators.openedHeight / 2
4367- compare(indicators.state!="initial", true,
4368- "Indicators should not be in initial state when partially opened.");
4369- }
4370-
4371- function test_progress_changes_state_to_locked() {
4372- indicators.height = indicators.openedHeight - indicators.panelHeight
4373- compare(indicators.state, "locked", "Indicators should be locked when fully opened.");
4374- }
4375-
4376- function test_partially_open() {
4377- indicators.height = indicators.openedHeight / 2
4378- compare(indicators.partiallyOpened, true,
4379- "Indicator should show as partially opened when height is half of openedHeight");
4380- compare(indicators.fullyOpened, false,
4381- "Indicator should not show as fully opened when height is half of openedHeight");
4382- }
4383-
4384- function test_fully_open() {
4385- indicators.height = indicators.openedHeight
4386- compare(indicators.partiallyOpened, false);
4387- compare(indicators.fullyOpened, true);
4388- }
4389-
4390- function init_invisible_indicator(identifier) {
4391- tryCompareFunction(function() { return findChild(indicators, identifier+"-delegate") !== undefined }, true);
4392- var item = findChild(indicators, identifier+"-delegate");
4393- verify(item !== null);
4394-
4395- item.enabled = false;
4396- }
4397-
4398- function test_row_visible_menuContent_visible_data() { return [
4399- {tag: "first", visible: [false, true, true, true, true] },
4400- {tag: "adjacent", visible: [true, false, false, true, true] },
4401- {tag: "bounds", visible: [false, true, true, true, false] },
4402- {tag: "disjoint", visible: [true, false, true, false, true] },
4403- {tag: "last", visible: [true, true, true, true, false] }];
4404- }
4405-
4406- function test_row_visible_menuContent_visible(data) {
4407- indicators.show();
4408-
4409- var contentListView = findChild(indicators, "indicatorsContentListView");
4410- var indicatorRowItems = findChild(indicators, "indicatorRowItems");
4411-
4412- var count = data.visible.length
4413- for (var i = 0; i< data.visible.length; i++) {
4414- if (data.visible[i] === false) {
4415- init_invisible_indicator("indicator-fake" + (i + 1));
4416- count--;
4417- }
4418- }
4419-
4420- tryCompare(indicatorRowItems, "count", count);
4421-
4422- for (i = 0; i < data.visible.length; i++) {
4423- var widgetName = "indicator-fake" + (i + 1 + "-widget");
4424- var pageName = "indicator-fake" + (i + 1 + "-page");
4425-
4426- // check for item
4427- tryCompareFunction(function() { return findChild(indicatorRowItems, widgetName) !== null }, data.visible[i]);
4428-
4429- // check for tab
4430- tryCompareFunction(function() { return findChild(contentListView, pageName) !== null }, data.visible[i]);
4431- }
4432- }
4433-
4434- function test_indicator_visible_correct_menu_data() { return [
4435- {tag: "current-first", currentIndex: 0, visible: [false, true, true, true, true], expectedIndex: 0, expextedMenu: "indicator-fake2" },
4436- {tag: "current-last", currentIndex: 4, visible: [true, true, true, true, false], expectedIndex: 3, expextedMenu: "indicator-fake4" },
4437- {tag: "after", currentIndex: 0, visible: [true, false, true, true, true], expectedIndex: 0, expextedMenu: "indicator-fake1" },
4438- {tag: "before", currentIndex: 1, visible: [false, true, true, true, true], expectedIndex: 1, expextedMenu: "indicator-fake2" }];
4439- }
4440-
4441- function test_indicator_visible_correct_menu(data) {
4442- var contentListView = findChild(indicators, "indicatorsContentListView");
4443- var indicatorRow = findChild(indicators, "indicatorRow");
4444-
4445- indicators.show();
4446- indicatorRow.setCurrentItemIndex(data.currentIndex);
4447- tryCompare(indicators, "fullyOpened", true);
4448-
4449- for (var i = 0; i< data.visible.length; i++) {
4450- if (data.visible[i] === false) {
4451- init_invisible_indicator("indicator-fake" + (i + 1));
4452- }
4453- }
4454-
4455- // check for current selected item
4456- tryCompare(indicatorRow, "currentItemIndex", data.expectedIndex);
4457-
4458- // check for current selected tab
4459- tryCompareFunction(function() { return findChild(contentListView, data.expextedMenu) === contentListView.currentItem }, true);
4460-
4461- }
4462- }
4463-}
4464
4465=== added file 'tests/qmltests/Panel/tst_IndicatorsBar.qml'
4466--- tests/qmltests/Panel/tst_IndicatorsBar.qml 1970-01-01 00:00:00 +0000
4467+++ tests/qmltests/Panel/tst_IndicatorsBar.qml 2014-10-21 21:16:05 +0000
4468@@ -0,0 +1,224 @@
4469+/*
4470+ * Copyright 2013-2014 Canonical Ltd.
4471+ *
4472+ * This program is free software; you can redistribute it and/or modify
4473+ * it under the terms of the GNU General Public License as published by
4474+ * the Free Software Foundation; version 3.
4475+ *
4476+ * This program is distributed in the hope that it will be useful,
4477+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
4478+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4479+ * GNU General Public License for more details.
4480+ *
4481+ * You should have received a copy of the GNU General Public License
4482+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
4483+ */
4484+
4485+import QtQuick 2.1
4486+import QtQuick.Layouts 1.1
4487+import QtTest 1.0
4488+import "../../../qml/Panel"
4489+import Ubuntu.Components 0.1
4490+import Unity.Test 0.1 as UT
4491+import Unity.Indicators 0.1 as Indicators
4492+
4493+IndicatorTest {
4494+ id: root
4495+ width: units.gu(100)
4496+ height: units.gu(40)
4497+
4498+
4499+ RowLayout {
4500+ anchors.fill: parent
4501+ anchors.margins: units.gu(1)
4502+
4503+ Rectangle {
4504+ id: itemArea
4505+ color: "blue"
4506+ Layout.fillWidth: true
4507+ Layout.fillHeight: true
4508+
4509+ Rectangle {
4510+ color: "black"
4511+ anchors.fill: indicatorsBar
4512+ }
4513+
4514+ IndicatorsBar {
4515+ id: indicatorsBar
4516+ height: expanded ? units.gu(7) : units.gu(3)
4517+ width: units.gu(30)
4518+ anchors.centerIn: parent
4519+ indicatorsModel: root.indicatorsModel
4520+ interactive: expanded && height === units.gu(7)
4521+
4522+ Behavior on height {
4523+ NumberAnimation {
4524+ id: heightAnimation
4525+ duration: UbuntuAnimation.FastDuration; easing: UbuntuAnimation.StandardEasing
4526+ }
4527+ }
4528+
4529+ MouseArea {
4530+ anchors.fill: parent
4531+ enabled: !indicatorsBar.expanded
4532+ onPressed: {
4533+ indicatorsBar.selectItemAt(mouse.x);
4534+ indicatorsBar.expanded = true
4535+ }
4536+ }
4537+ }
4538+ }
4539+
4540+ ColumnLayout {
4541+ Layout.alignment: Qt.AlignTop
4542+ Layout.fillWidth: false
4543+
4544+ Button {
4545+ Layout.fillWidth: true
4546+ text: indicatorsBar.expanded ? "Collapse" : "Expand"
4547+ onClicked: indicatorsBar.expanded = !indicatorsBar.expanded
4548+ }
4549+
4550+ Rectangle {
4551+ Layout.preferredHeight: units.dp(1);
4552+ Layout.fillWidth: true;
4553+ color: "black"
4554+ }
4555+
4556+ Repeater {
4557+ model: root.originalModelData
4558+ RowLayout {
4559+ CheckBox {
4560+ checked: true
4561+ onCheckedChanged: checked ? insertIndicator(index) : removeIndicator(index);
4562+ }
4563+ Label {
4564+ Layout.fillWidth: true
4565+ text: modelData["identifier"]
4566+ }
4567+
4568+ CheckBox {
4569+ checked: true
4570+ onCheckedChanged: setIndicatorVisible(index, checked);
4571+ }
4572+ Label {
4573+ text: "visible"
4574+ }
4575+ }
4576+ }
4577+ }
4578+ }
4579+
4580+ UT.UnityTestCase {
4581+ name: "IndicatorsBar"
4582+ when: windowShown
4583+
4584+ function init() {
4585+ indicatorsBar.expanded = false;
4586+ wait_for_expansion_to_settle();
4587+ }
4588+
4589+ function test_expandSelectedItem_data() {
4590+ return [
4591+ { index: 0 },
4592+ { index: 2 },
4593+ { index: 4 }
4594+ ];
4595+ }
4596+
4597+ function wait_for_expansion_to_settle() {
4598+ tryCompare(heightAnimation, "running", false);
4599+ wait(UbuntuAnimation.SnapDuration); // put a little extra wait in for things to settle
4600+ }
4601+
4602+ // Rough check that expanding a selected item keeps it within the area of the original item.
4603+ function test_expandSelectedItem(data) {
4604+ var dataItem = findChild(indicatorsBar, root.originalModelData[data.index]["identifier"] + "-panelItem");
4605+ verify(dataItem !== null);
4606+
4607+ var mappedPosition = indicatorsBar.mapFromItem(dataItem, dataItem.width/2, dataItem.height/2);
4608+
4609+ indicatorsBar.selectItemAt(mappedPosition.x);
4610+ indicatorsBar.expanded = true;
4611+ wait_for_expansion_to_settle();
4612+
4613+
4614+ // mappedPosition contained within mappedRect
4615+ tryCompareFunction(function() {
4616+ var mappedRect = indicatorsBar.mapFromItem(dataItem, 0, 0, dataItem.width, dataItem.height);
4617+ return mappedRect.x <= mappedPosition.x; },
4618+ true);
4619+ tryCompareFunction(function() {
4620+ var mappedRect = indicatorsBar.mapFromItem(dataItem, 0, 0, dataItem.width, dataItem.height);
4621+ return mappedRect.x + mappedRect.width >= mappedPosition.x;
4622+ }, true);
4623+ }
4624+
4625+ function test_scrollOffset() {
4626+ indicatorsBar.expanded = true;
4627+ wait_for_expansion_to_settle();
4628+
4629+ var lastItemIndex = root.originalModelData.length-1;
4630+ var dataItem = findChild(indicatorsBar, root.originalModelData[lastItemIndex]["identifier"] + "-panelItem");
4631+ verify(dataItem !== null);
4632+
4633+ var row = findChild(indicatorsBar, "indicatorItemRow");
4634+ // test will not work without these conditions
4635+ verify(row.width >= indicatorsBar.width + dataItem.width);
4636+
4637+ var mappedPosition = indicatorsBar.mapFromItem(dataItem, dataItem.width/2, dataItem.height/2);
4638+ indicatorsBar.addScrollOffset(-dataItem.width);
4639+ var newMappedPosition = indicatorsBar.mapFromItem(dataItem, dataItem.width/2, dataItem.height/2);
4640+
4641+ compare(mappedPosition.x, newMappedPosition.x - dataItem.width);
4642+ }
4643+
4644+ function test_selectItemWhenExpanded_data() {
4645+ return [
4646+ { index: 3 },
4647+ { index: 4 }
4648+ ];
4649+ }
4650+
4651+ function test_selectItemWhenExpanded(data) {
4652+ indicatorsBar.expanded = true;
4653+ wait_for_expansion_to_settle();
4654+
4655+ var dataItem = findChild(indicatorsBar, root.originalModelData[data.index]["identifier"] + "-panelItem");
4656+ if (indicatorsBar.mapFromItem(dataItem, dataItem.width/2, dataItem.height/2).x < 0) {
4657+ skip("Out of bounds");
4658+ }
4659+ mouseClick(dataItem, dataItem.width/2, dataItem.height/2);
4660+ verify(dataItem.selected === true);
4661+ }
4662+
4663+ function test_visibleIndicators_data() {
4664+ return [
4665+ { visible: [true, false, true, false, true, true] },
4666+ { visible: [false, false, false, false, false, false] }
4667+ ];
4668+ }
4669+
4670+ function test_visibleIndicators(data) {
4671+ for (var i = 0; i < data.visible.length; i++) {
4672+ var visible = data.visible[i];
4673+ root.setIndicatorVisible(i, visible);
4674+
4675+ var dataItem = findChild(indicatorsBar, root.originalModelData[i]["identifier"] + "-panelItem");
4676+ tryCompare(dataItem, "opacity", visible ? 1.0 : 0.0);
4677+ tryCompareFunction(function() { return dataItem.width > 0.0; }, visible);
4678+ }
4679+
4680+ indicatorsBar.expanded = true;
4681+ wait_for_expansion_to_settle();
4682+
4683+ for (var i = 0; i < data.visible.length; i++) {
4684+ root.setIndicatorVisible(i, data.visible[i]);
4685+
4686+ var dataItem = findChild(indicatorsBar, root.originalModelData[i]["identifier"] + "-panelItem");
4687+ tryCompareFunction(function() { return dataItem.opacity > 0.0; }, true);
4688+ tryCompareFunction(function() { return dataItem.width > 0.0; }, true);
4689+ }
4690+ }
4691+ }
4692+}
4693
4694=== added file 'tests/qmltests/Panel/tst_IndicatorsMenu.qml'
4695--- tests/qmltests/Panel/tst_IndicatorsMenu.qml 1970-01-01 00:00:00 +0000
4696+++ tests/qmltests/Panel/tst_IndicatorsMenu.qml 2014-10-21 21:16:05 +0000
4697@@ -0,0 +1,258 @@
4698+/*
4699+ * Copyright 2013-2014 Canonical Ltd.
4700+ *
4701+ * This program is free software; you can redistribute it and/or modify
4702+ * it under the terms of the GNU General Public License as published by
4703+ * the Free Software Foundation; version 3.
4704+ *
4705+ * This program is distributed in the hope that it will be useful,
4706+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
4707+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4708+ * GNU General Public License for more details.
4709+ *
4710+ * You should have received a copy of the GNU General Public License
4711+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
4712+ */
4713+
4714+import QtQuick 2.1
4715+import QtQuick.Layouts 1.1
4716+import QtTest 1.0
4717+import "../../../qml/Panel"
4718+import Ubuntu.Components 0.1
4719+import Unity.Test 0.1 as UT
4720+import Unity.Indicators 0.1 as Indicators
4721+
4722+IndicatorTest {
4723+ id: root
4724+ width: units.gu(80)
4725+ height: units.gu(71)
4726+ color: "white"
4727+
4728+ property string indicatorProfile: "phone"
4729+
4730+ RowLayout {
4731+ anchors.fill: parent
4732+ anchors.margins: units.gu(1)
4733+
4734+ Rectangle {
4735+ Layout.fillWidth: true
4736+ Layout.fillHeight: true
4737+
4738+ id: itemArea
4739+ color: "blue"
4740+
4741+ IndicatorsMenu {
4742+ id: indicatorsMenu
4743+ width: units.gu(40)
4744+ anchors {
4745+ top: parent.top
4746+ right: parent.right
4747+ }
4748+ minimizedPanelHeight: units.gu(3)
4749+ expandedPanelHeight: units.gu(7)
4750+ openedHeight: parent.height
4751+ indicatorsModel: root.indicatorsModel
4752+ shown: false
4753+ }
4754+ }
4755+
4756+ ColumnLayout {
4757+ Layout.alignment: Qt.AlignTop
4758+ Layout.fillWidth: false
4759+
4760+ Button {
4761+ Layout.fillWidth: true
4762+ text: indicatorsMenu.shown ? "Hide" : "Show"
4763+ onClicked: {
4764+ if (indicatorsMenu.shown) {
4765+ indicatorsMenu.hide();
4766+ } else {
4767+ indicatorsMenu.show();
4768+ }
4769+ }
4770+ }
4771+
4772+ Rectangle {
4773+ Layout.preferredHeight: units.dp(1);
4774+ Layout.fillWidth: true;
4775+ color: "black"
4776+ }
4777+
4778+ Repeater {
4779+ model: root.originalModelData
4780+ RowLayout {
4781+ CheckBox {
4782+ checked: true
4783+ onCheckedChanged: checked ? insertIndicator(index) : removeIndicator(index);
4784+ }
4785+ Label {
4786+ Layout.fillWidth: true
4787+ text: modelData["identifier"]
4788+ }
4789+
4790+ CheckBox {
4791+ checked: true
4792+ onCheckedChanged: setIndicatorVisible(index, checked);
4793+ }
4794+ Label {
4795+ text: "visible"
4796+ }
4797+ }
4798+ }
4799+ }
4800+ }
4801+
4802+ UT.UnityTestCase {
4803+ id: testCase
4804+ name: "IndicatorsMenu"
4805+ when: windowShown
4806+
4807+ function init() {
4808+ indicatorsMenu.hide();
4809+ tryCompare(indicatorsMenu.hideAnimation, "running", false);
4810+ compare(indicatorsMenu.state, "initial");
4811+
4812+ indicatorsMenu.verticalVelocityThreshold = 0.5
4813+ }
4814+
4815+ function get_indicator_item(index) {
4816+ var indicatorItem = findChild(indicatorsMenu, root.originalModelData[index]["identifier"] + "-panelItem");
4817+ verify(indicatorItem !== null);
4818+
4819+ return indicatorItem;
4820+ }
4821+
4822+ // Showing the indicators should fully open the indicator panel.
4823+ function test_showAndHide() {
4824+ indicatorsMenu.show();
4825+ tryCompare(indicatorsMenu, "fullyOpened", true);
4826+
4827+ indicatorsMenu.hide();
4828+ tryCompare(indicatorsMenu, "fullyClosed", true);
4829+ }
4830+
4831+ // Test that closing the indicators ends up in the correct position.
4832+ function test_hideEndsInCorrectPosition() {
4833+ var indicatorsBar = findChild(indicatorsMenu, "indicatorsBar");
4834+ var flickable = findChild(indicatorsBar, "flickable");
4835+
4836+ var originalContentX = flickable.contentX;
4837+
4838+ indicatorsMenu.show();
4839+ indicatorsBar.setCurrentItemIndex(0);
4840+ tryCompare(indicatorsMenu, "fullyOpened", true);
4841+
4842+ indicatorsMenu.hide();
4843+ tryCompare(flickable, "contentX", originalContentX);
4844+ }
4845+
4846+ function test_progress_changes_state_to_reveal() {
4847+ indicatorsMenu.height = indicatorsMenu.openedHeight / 2;
4848+ compare(indicatorsMenu.state, "reveal", "Indicators should be revealing when partially opened.");
4849+
4850+ indicatorsMenu.height = indicatorsMenu.openedHeight;
4851+ compare(indicatorsMenu.state, "reveal", "Indicators should still be revealing when fully opened.");
4852+ }
4853+
4854+ function test_open_state() {
4855+ compare(indicatorsMenu.fullyClosed, true, "Indicator should show as fully closed.");
4856+ compare(indicatorsMenu.partiallyOpened, false, "Indicator should not show as partially opened");
4857+ compare(indicatorsMenu.fullyOpened, false, "Indicator should not show as fully opened");
4858+
4859+ indicatorsMenu.height = indicatorsMenu.openedHeight / 2
4860+ compare(indicatorsMenu.fullyClosed, false, "Indicator should not show as fully closed.");
4861+ compare(indicatorsMenu.partiallyOpened, true, "Indicator should show as partially opened");
4862+ compare(indicatorsMenu.fullyOpened, false, "Indicator should not show as fully opened");
4863+
4864+ indicatorsMenu.height = indicatorsMenu.openedHeight;
4865+ compare(indicatorsMenu.fullyClosed, false, "Indicator should not show as fully closed.");
4866+ compare(indicatorsMenu.partiallyOpened, false, "Indicator should show as partially opened");
4867+ compare(indicatorsMenu.fullyOpened, true, "Indicator should not show as fully opened");
4868+ }
4869+
4870+ // Pressing on the indicator panel should activate the indicator hints
4871+ // and expose the header
4872+ function test_hint() {
4873+ var indicatorItem = get_indicator_item(0);
4874+ var mappedPosition = root.mapFromItem(indicatorItem, indicatorItem.width/2, indicatorItem.height/2);
4875+
4876+ touchPress(indicatorsMenu, mappedPosition.x, indicatorsMenu.minimizedPanelHeight / 2);
4877+
4878+ // hint animation should be run, meaning that indicators will move downwards
4879+ // by hintValue pixels without any drag taking place
4880+ tryCompareFunction(function() { return indicatorsMenu.height }, indicatorsMenu.expandedPanelHeight + units.gu(2));
4881+ tryCompare(indicatorsMenu, "partiallyOpened", true);
4882+
4883+ touchRelease(indicatorsMenu, mappedPosition.x, indicatorsMenu.minimizedPanelHeight / 2);
4884+ }
4885+
4886+ // tests swiping on an indicator item activates the correct item.
4887+ function test_swipeForCurrentItem()
4888+ {
4889+ var indicatorItemRow = findChild(indicatorsMenu, "indicatorItemRow");
4890+ verify(indicatorItemRow !== null);
4891+
4892+ for (var i = 0; i < root.originalModelData.length; i++) {
4893+ var indicatorItem = get_indicator_item(i);
4894+
4895+ var mappedPosition = root.mapFromItem(indicatorItem, indicatorItem.width/2, indicatorItem.height/2);
4896+
4897+ touchFlick(indicatorsMenu,
4898+ mappedPosition.x, mappedPosition.y,
4899+ mappedPosition.x, indicatorsMenu.openedHeight / 2,
4900+ true /* beginTouch */, false /* endTouch */);
4901+
4902+ compare(indicatorItemRow.currentItem, indicatorItem,
4903+ "Incorrect item activated at position " + i);
4904+
4905+ touchFlick(indicatorItemRow,
4906+ mappedPosition.x, indicatorsMenu.openedHeight / 2,
4907+ mappedPosition.x, mappedPosition.y,
4908+ false /* beginTouch */, true /* endTouch */);
4909+
4910+ // wait until fully closed
4911+ tryCompare(indicatorsMenu, "fullyClosed", true);
4912+ }
4913+ }
4914+
4915+ // Test the vertical velocity check when flicking the indicators open at an angle.
4916+ // If the vertical velocity is above a specific point, we shouldnt change active indicators
4917+ // if the x position changes
4918+ function test_verticalVelocityDetector() {
4919+ indicatorsMenu.verticalVelocityThreshold = 0;
4920+ verify(root.originalModelData.length >= 2);
4921+
4922+ var indicatorItemRow = findChild(indicatorsMenu, "indicatorItemRow");
4923+ verify(indicatorItemRow !== null);
4924+
4925+ // Get the first indicator
4926+ var firstItem = get_indicator_item(0);
4927+ var firstItemMappedPosition = root.mapFromItem(firstItem, firstItem.width/2, firstItem.height/2);
4928+
4929+ // 1) Drag the mouse down to hint a bit
4930+ touchFlick(indicatorsMenu,
4931+ firstItemMappedPosition.x, indicatorsMenu.minimizedPanelHeight / 2,
4932+ firstItemMappedPosition.x, indicatorsMenu.minimizedPanelHeight * 2,
4933+ true /* beginTouch */, false /* endTouch */);
4934+
4935+ tryCompare(indicatorItemRow, "currentItem", firstItem)
4936+
4937+ // next time position will have moved.
4938+ var nextItem = get_indicator_item(1);
4939+ var nextItemMappedPosition = root.mapFromItem(nextItem, nextItem.width/2, nextItem.height/2);
4940+
4941+ // 1) Flick mouse down to bottom
4942+ touchFlick(indicatorsMenu,
4943+ firstItemMappedPosition.x, indicatorsMenu.minimizedPanelHeight * 2,
4944+ nextItemMappedPosition.x, indicatorsMenu.openedHeight / 3,
4945+ false /* beginTouch */, false /* endTouch */,
4946+ units.gu(50) /* speed */, 5 /* iterations */); // more samples needed for accurate velocity
4947+
4948+ compare(indicatorItemRow.currentItem, firstItem, "First indicator should still be the current item");
4949+ // after waiting in the same spot with touch down, it should update to the next item.
4950+ tryCompare(indicatorItemRow, "currentItem", nextItem);
4951+
4952+ touchRelease(indicatorsMenu, nextItemMappedPosition.x, indicatorsMenu.openedHeight / 3);
4953+ }
4954+ }
4955+}
4956
4957=== modified file 'tests/qmltests/Panel/tst_MenuContent.qml'
4958--- tests/qmltests/Panel/tst_MenuContent.qml 2014-10-21 21:16:04 +0000
4959+++ tests/qmltests/Panel/tst_MenuContent.qml 2014-10-21 21:16:05 +0000
4960@@ -1,5 +1,5 @@
4961 /*
4962- * Copyright 2013 Canonical Ltd.
4963+ * Copyright 2013-2014 Canonical Ltd.
4964 *
4965 * This program is free software; you can redistribute it and/or modify
4966 * it under the terms of the GNU General Public License as published by
4967@@ -17,12 +17,11 @@
4968 import QtQuick 2.0
4969 import QtTest 1.0
4970 import Unity.Test 0.1 as UT
4971-import ".."
4972 import "../../../qml/Panel"
4973 import Unity.Indicators 0.1 as Indicators
4974
4975-Item {
4976- id: shell
4977+IndicatorTest {
4978+ id: root
4979 width: units.gu(40)
4980 height: units.gu(70)
4981
4982@@ -30,15 +29,9 @@
4983 Item { id: greeter }
4984 Item { id: handle }
4985
4986-
4987- Indicators.IndicatorsModel {
4988- id: indicatorsModel
4989- Component.onCompleted: load("test1")
4990- }
4991-
4992 MenuContent {
4993 id: menuContent
4994- indicatorsModel: indicatorsModel
4995+ indicatorsModel: root.indicatorsModel
4996 height: parent.height - 50
4997 }
4998
4999@@ -70,12 +63,12 @@
5000 if (menuContent.currentMenuIndex == -1)
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches