on xenial help sign in
Only show top tutorial after 3s of inactivity
commit1e10d9f7b7258df3fc11ca98b7496116b87cb81f authorMichael Terry <michael.terry@canonical.com> dateFri 13 Nov 2015, 16:54 (11 years ago) parent51d5a69
11 files changed+83−49
plugins/Utils/CMakeLists.txt+1−1 plugins/Utils/Utils.qmltypes+2−2 plugins/Utils/plugin.cpp+2−2 plugins/Utils/windowkeysfilter.cpp → plugins/Utils/windowinputfilter.cpp+14−16 plugins/Utils/windowkeysfilter.h → plugins/Utils/windowinputfilter.h+11−11 qml/Shell.qml+4−4 qml/Tutorial/Tutorial.qml+7 qml/Tutorial/TutorialContent.qml+37−8 tests/mocks/Utils/CMakeLists.txt+1−1 tests/mocks/Utils/Utils.qmltypes+2−2 tests/mocks/Utils/plugin.cpp+2−2
plugins/Utils/CMakeLists.txt+1−1
@@ -17,7 +17,7 @@ set(QMLPLUGIN_SRC
1717 unitysortfilterproxymodelqml.cpp
1818 Timer.cpp
1919 unitymenumodelpaths.cpp
20− windowkeysfilter.cpp
20+ windowinputfilter.cpp
2121 windowscreenshotprovider.cpp
2222 easingcurve.cpp
2323 windowstatestorage.cpp
plugins/Utils/Utils.qmltypes+2−2
@@ -147,10 +147,10 @@ Module {
147147 }
148148 }
149149 Component {
150− name: "WindowKeysFilter"
150+ name: "WindowInputFilter"
151151 defaultProperty: "data"
152152 prototype: "QQuickItem"
153− exports: ["Utils/WindowKeysFilter 0.1"]
153+ exports: ["Utils/WindowInputFilter 0.1"]
154154 exportMetaObjectRevisions: [0]
155155 }
156156 Component {
plugins/Utils/plugin.cpp+2−2
@@ -30,7 +30,7 @@
3030#include "qlimitproxymodelqml.h"
3131#include "unitysortfilterproxymodelqml.h"
3232#include "unitymenumodelpaths.h"
33−#include "windowkeysfilter.h"
33+#include "windowinputfilter.h"
3434#include "windowscreenshotprovider.h"
3535#include "windowstatestorage.h"
3636#include "constants.h"
@@ -58,7 +58,7 @@ void UtilsPlugin::registerTypes(const char *uri)
5858 qmlRegisterType<QLimitProxyModelQML>(uri, 0, 1, "LimitProxyModel");
5959 qmlRegisterType<UnitySortFilterProxyModelQML>(uri, 0, 1, "UnitySortFilterProxyModel");
6060 qmlRegisterType<UnityMenuModelPaths>(uri, 0, 1, "UnityMenuModelPaths");
61− qmlRegisterType<WindowKeysFilter>(uri, 0, 1, "WindowKeysFilter");
61+ qmlRegisterType<WindowInputFilter>(uri, 0, 1, "WindowInputFilter");
6262 qmlRegisterType<EasingCurve>(uri, 0, 1, "EasingCurve");
6363 qmlRegisterSingletonType<WindowStateStorage>(uri, 0, 1, "WindowStateStorage", createWindowStateStorage);
6464 qmlRegisterType<InputWatcher>(uri, 0, 1, "InputWatcher");
plugins/Utils/windowkeysfilter.cpp → plugins/Utils/windowinputfilter.cpprenamed+14−16
@@ -16,36 +16,34 @@
1616 * Author: Daniel d'Andrada <daniel.dandrada@canonical.com>
1717 */
1818
19−#include "windowkeysfilter.h"
19+#include "windowinputfilter.h"
2020
2121#include <QQuickWindow>
2222
23−WindowKeysFilter::WindowKeysFilter(QQuickItem *parent)
23+WindowInputFilter::WindowInputFilter(QQuickItem *parent)
2424 : QQuickItem(parent),
25− m_currentEventTimestamp(0)
25+ m_lastInputTimestamp(0)
2626{
2727 connect(this, &QQuickItem::windowChanged,
28− this, &WindowKeysFilter::setupFilterOnWindow);
28+ this, &WindowInputFilter::setupFilterOnWindow);
2929}
3030
31−bool WindowKeysFilter::eventFilter(QObject *watched, QEvent *event)
31+bool WindowInputFilter::eventFilter(QObject *watched, QEvent *event)
3232{
3333 Q_ASSERT(!m_filteredWindow.isNull());
3434 Q_ASSERT(watched == static_cast<QObject*>(m_filteredWindow.data()));
3535 Q_UNUSED(watched);
3636
37+ QInputEvent *inputEvent = dynamic_cast<QInputEvent*>(event);
38+ if (inputEvent) {
39+ m_lastInputTimestamp = inputEvent->timestamp();
40+ Q_EMIT lastInputTimestampChanged();
41+ }
42+
3743 if (event->type() == QEvent::KeyPress || event->type() == QEvent::KeyRelease) {
3844 // Let QML see this event and decide if it does not want it
3945 event->accept();
40−
41− m_currentEventTimestamp = static_cast<QInputEvent*>(event)->timestamp();
42− Q_EMIT currentEventTimestampChanged();
43−
4446 QCoreApplication::sendEvent(this, event);
45−
46− m_currentEventTimestamp = 0;
47− Q_EMIT currentEventTimestampChanged();
48−
4947 return event->isAccepted();
5048 } else {
5149 // Not interested
@@ -53,7 +51,7 @@ bool WindowKeysFilter::eventFilter(QObject *watched, QEvent *event)
5351 }
5452}
5553
56−void WindowKeysFilter::setupFilterOnWindow(QQuickWindow *window)
54+void WindowInputFilter::setupFilterOnWindow(QQuickWindow *window)
5755{
5856 if (!m_filteredWindow.isNull()) {
5957 m_filteredWindow->removeEventFilter(this);
@@ -66,7 +64,7 @@ void WindowKeysFilter::setupFilterOnWindow(QQuickWindow *window)
6664 }
6765}
6866
69−ulong WindowKeysFilter::currentEventTimestamp() const
67+ulong WindowInputFilter::lastInputTimestamp() const
7068{
71− return m_currentEventTimestamp;
69+ return m_lastInputTimestamp;
7270}
plugins/Utils/windowkeysfilter.h → plugins/Utils/windowinputfilter.hrenamed+11−11
@@ -16,8 +16,8 @@
1616 * Author: Daniel d'Andrada <daniel.dandrada@canonical.com>
1717 */
1818
19−#ifndef UNITY_WINDOWKEYSFILTER_H
20−#define UNITY_WINDOWKEYSFILTER_H
19+#ifndef UNITY_WINDOWINPUTFILTER_H
20+#define UNITY_WINDOWINPUTFILTER_H
2121
2222#include <QQuickItem>
2323#include <QPointer>
@@ -29,30 +29,30 @@
2929 accepted ones will be filtered out. Events are accepted by default, so make sure you reject
3030 the keys you're not interested in.
3131
32− If more than one WindowKeysFilter exist in the same QML scene (and thus in the same QQuickWindow)
32+ If more than one WindowInputFilter exist in the same QML scene (and thus in the same QQuickWindow)
3333 they will be called in the order of creation, which can be tricky to assess. So the best practice
34− is to have at most one WindowKeysFilter per QML scene.
34+ is to have at most one WindowInputFilter per QML scene.
3535 */
36−class WindowKeysFilter : public QQuickItem
36+class WindowInputFilter : public QQuickItem
3737{
3838 Q_OBJECT
39− Q_PROPERTY(ulong currentEventTimestamp READ currentEventTimestamp NOTIFY currentEventTimestampChanged)
39+ Q_PROPERTY(ulong lastInputTimestamp READ lastInputTimestamp NOTIFY lastInputTimestampChanged)
4040public:
41− WindowKeysFilter(QQuickItem *parent = 0);
41+ WindowInputFilter(QQuickItem *parent = 0);
4242
4343 bool eventFilter(QObject *watched, QEvent *event) override;
4444
45− ulong currentEventTimestamp() const;
45+ ulong lastInputTimestamp() const;
4646
4747Q_SIGNALS:
48− void currentEventTimestampChanged();
48+ void lastInputTimestampChanged();
4949
5050private Q_SLOTS:
5151 void setupFilterOnWindow(QQuickWindow *window);
5252
5353private:
5454 QPointer<QQuickWindow> m_filteredWindow;
55− ulong m_currentEventTimestamp;
55+ ulong m_lastInputTimestamp;
5656};
5757
58−#endif // UNITY_WINDOWKEYSFILTER_H
58+#endif // UNITY_WINDOWINPUTFILTER_H
qml/Shell.qml+4−4
@@ -24,7 +24,7 @@ import Ubuntu.Gestures 0.1
2424import Ubuntu.Telephony 0.1 as Telephony
2525import Unity.Connectivity 0.1
2626import Unity.Launcher 0.1
27−import GlobalShortcut 1.0 // has to be before Utils, because of WindowKeysFilter
27+import GlobalShortcut 1.0 // has to be before Utils, because of WindowInputFilter
2828import Utils 0.1
2929import Powerd 0.1
3030import SessionBroadcast 0.1
@@ -171,9 +171,9 @@ Item {
171171 // dummy shortcut to force creation of GlobalShortcutRegistry before WindowKeyFilter
172172 }
173173
174− WindowKeysFilter {
175− Keys.onPressed: physicalKeysMapper.onKeyPressed(event, currentEventTimestamp);
176− Keys.onReleased: physicalKeysMapper.onKeyReleased(event, currentEventTimestamp);
174+ WindowInputFilter {
175+ Keys.onPressed: physicalKeysMapper.onKeyPressed(event, lastInputTimestamp);
176+ Keys.onReleased: physicalKeysMapper.onKeyReleased(event, lastInputTimestamp);
177177 }
178178
179179 HomeKeyWatcher {
qml/Tutorial/Tutorial.qml+7
@@ -34,6 +34,7 @@ Item {
3434 property string usageScenario
3535 property bool paused
3636 property bool keyboardVisible
37+ property int lastInputTimestamp
3738
3839 readonly property bool launcherEnabled: loader.item ? loader.item.launcherEnabled : true
3940 readonly property bool spreadEnabled: loader.item ? loader.item.spreadEnabled : true
@@ -88,6 +89,12 @@ Item {
8889 value: root.keyboardVisible
8990 }
9091
92+ Binding {
93+ target: loader.item
94+ property: "lastInputTimestamp"
95+ value: root.lastInputTimestamp
96+ }
97+
9198 Connections {
9299 target: loader.item
93100 onFinished: AccountsService.demoEdges = false
qml/Tutorial/TutorialContent.qml+37−8
@@ -28,6 +28,7 @@ Item {
2828 property string usageScenario
2929 property bool paused
3030 property bool keyboardVisible
31+ property var lastInputTimestamp
3132
3233 readonly property bool launcherEnabled: !running || tutorialLeft.shown
3334 readonly property bool spreadEnabled: !running || tutorialRight.shown
@@ -76,16 +77,36 @@ Item {
7677 || AccountsService.demoEdgesCompleted.indexOf("top") != -1
7778 isReady: tutorialLeft.skipped && !skipped && !paused && !keyboardVisible && !tutorialBottom.shown
7879
80+ // We fire 30s after left edge tutorial, with at least 3s of inactivity
81+
7982 Timer {
80− id: tutorialTopTimer
81− objectName: "tutorialTopTimer"
82− interval: 30000
83− onTriggered: if (tutorialTop.isReady && !tutorialTop.shown) tutorialTop.show()
83+ id: tutorialTopInactivityTimer
84+ objectName: "tutorialTopInactivityTimer"
85+ interval: 3000
86+
87+ Connections {
88+ target: root
89+ onLastInputTimestampChanged: {
90+ if (tutorialTopInactivityTimer.running) {
91+ tutorialTopInactivityTimer.restart();
92+ }
93+ }
94+ }
95+
96+ onTriggered: {
97+ if (tutorialTop.isReady) {
98+ tutorialTop.show();
99+ } else {
100+ restart();
101+ }
102+ }
84103 }
85104
86− Connections {
87− target: AccountsService
88− onDemoEdgesCompletedChanged: if (tutorialTop.isReady && !tutorialTop.shown) tutorialTopTimer.start()
105+ Timer {
106+ id: tutorialTopTimer
107+ objectName: "tutorialTopTimer"
108+ interval: 27000
109+ onTriggered: tutorialTopInactivityTimer.start()
89110 }
90111
91112 onSkippedChanged: if (skipped && shown) hide()
@@ -110,7 +131,15 @@ Item {
110131 id: tutorialRightTimer
111132 objectName: "tutorialRightTimer"
112133 interval: 3000
113− onTriggered: if (tutorialRight.isReady && !tutorialRight.shown) tutorialRight.show()
134+ onTriggered: {
135+ if (tutorialRight.isReady) {
136+ if (!tutorialRight.shown) {
137+ tutorialRight.show();
138+ }
139+ } else {
140+ restart();
141+ }
142+ }
114143 }
115144
116145 Connections {
tests/mocks/Utils/CMakeLists.txt+1−1
@@ -14,7 +14,7 @@ set(QMLPLUGIN_SRC
1414 ${CMAKE_SOURCE_DIR}/plugins/Utils/qlimitproxymodelqml.cpp
1515 ${CMAKE_SOURCE_DIR}/plugins/Utils/unitysortfilterproxymodelqml.cpp
1616 ${CMAKE_SOURCE_DIR}/plugins/Utils/unitymenumodelpaths.cpp
17− ${CMAKE_SOURCE_DIR}/plugins/Utils/windowkeysfilter.cpp
17+ ${CMAKE_SOURCE_DIR}/plugins/Utils/windowinputfilter.cpp
1818 ${CMAKE_SOURCE_DIR}/plugins/Utils/windowscreenshotprovider.cpp
1919 ${CMAKE_SOURCE_DIR}/plugins/Utils/easingcurve.cpp
2020 ${CMAKE_SOURCE_DIR}/plugins/Utils/inputwatcher.cpp
tests/mocks/Utils/Utils.qmltypes+2−2
@@ -145,10 +145,10 @@ Module {
145145 }
146146 }
147147 Component {
148− name: "WindowKeysFilter"
148+ name: "WindowInputFilter"
149149 defaultProperty: "data"
150150 prototype: "QQuickItem"
151− exports: ["Utils/WindowKeysFilter 0.1"]
151+ exports: ["Utils/WindowInputFilter 0.1"]
152152 exportMetaObjectRevisions: [0]
153153 }
154154 Component {
tests/mocks/Utils/plugin.cpp+2−2
@@ -32,7 +32,7 @@
3232#include <qlimitproxymodelqml.h>
3333#include <unitysortfilterproxymodelqml.h>
3434#include <unitymenumodelpaths.h>
35−#include <windowkeysfilter.h>
35+#include <windowinputfilter.h>
3636#include <windowscreenshotprovider.h>
3737#include <easingcurve.h>
3838
@@ -57,7 +57,7 @@ void FakeUtilsPlugin::registerTypes(const char *uri)
5757 qmlRegisterType<QLimitProxyModelQML>(uri, 0, 1, "LimitProxyModel");
5858 qmlRegisterType<UnitySortFilterProxyModelQML>(uri, 0, 1, "UnitySortFilterProxyModel");
5959 qmlRegisterType<UnityMenuModelPaths>(uri, 0, 1, "UnityMenuModelPaths");
60− qmlRegisterType<WindowKeysFilter>(uri, 0, 1, "WindowKeysFilter");
60+ qmlRegisterType<WindowInputFilter>(uri, 0, 1, "WindowInputFilter");
6161 qmlRegisterType<EasingCurve>(uri, 0, 1, "EasingCurve");
6262 qmlRegisterSingletonType<WindowStateStorage>(uri, 0, 1, "WindowStateStorage", createWindowStateStorage);
6363 qmlRegisterType<InputWatcher>(uri, 0, 1, "InputWatcher");