We have moved to a new Sailfish OS Forum. Please start new discussions there.
8

How to overwrite system gestures for a native app?

asked 2018-12-29 19:22:24 +0300

jsommer gravatar image

I'm working on a nataive app, that overwrites partly a system edge swipe from the bottom edges. I was told, that I can implement this feature by using QWindow::setFlags() with the value Qt.WindowOverridesSystemGestures.

Sailfish Apps are using the Silica AppplicationWindow as their root UI element. I expected, that this class inherits the QtQuick ApplicationWindow that again inherits the properties and methods of the QtQuick Window with the property flags. This seems to be wrong, because the SDK and the log output report an error:

Cannot assign to non-existent property "flags" 
         flags: Qt.WindowOverridesSystemGestures

Do I have to implement an app without Silica? With this approach I would loose the Sailfish look and feel. I think, it is somehow possible to implement the said requirement with a Sailfish Silica app, because the Sailfish tutorial app overwrites system gestures either.

The next challange would be to implement additional system gestures. I'm quite new at Qt development and I'm missign the clear MVC paradigm I used to implement for Java apps for Android or Objective-C and Swift apps for macOS and iOS. UWP Windows app are using a different MVVM paradigm.

However I would expect to implement window controller (Objective-C, Swift) or event listener (Java) by overwriting methods for event handlung for the said use case and hand over further use cases by calling somethink like super.swipeEvent(event). I can't find methods for swipe or gesture events in any QML type that I could use.

I'll checkout the IRC client project. The uses a swipe geture to call drawers form the left and right side. Maybe I can use this approach. Suggestions, recommendations or links to open source projects, which have implemented a similar requirement, are welcome.

edit retag flag offensive close delete

Comments

Have you already looked into the Backup thingy in Settings? All gestures are disables during the Backup. If you take a look at the QML files of the app you will find some QML code that blocks all gestures. They use the same flags you mentioned I think. The internals of the component that's responsible for disabling the gestures can be found on Coderus Github page (better sailfish qml components)

Dylan Van Assche ( 2018-12-29 22:48:49 +0300 )edit

Sounds like a good idea. Do you know the system path for this settings? Are these settings located, where other apps are installed?

Do you also have an idea to capture swipe or gesture events in QML?

jsommer ( 2018-12-30 13:37:07 +0300 )edit
1

I think it's very bad practice to override system gestures unless there's a good reason to do this, such as blocking them for security issues (e. g. ask for confirmation before closing a critical app).

Giacomo Di Giacomo ( 2019-01-01 19:28:17 +0300 )edit

@Giacomo. Indeed, but in my case, it is a prototype app, that demostrated additional system gestures for a fork or patch of the Sailfish lipstick implementation we will implement in collaboration with Jolla.

jsommer ( 2019-01-02 10:28:50 +0300 )edit

2 Answers

Sort by » oldest newest most voted
6

answered 2019-03-08 19:37:44 +0300

jsommer gravatar image

updated 2019-03-09 00:38:50 +0300

With the help of a Jolla engineer (paljon kiitoksia) I learned, that I can use WindowGestureOverride for my purpose. You can find examples in the Compositor.qml on your Sailfish device. First I have to import the libraries:

import Sailfish.Silica 1.0
import Sailfish.Lipstick 1.0
import Sailfish.Silica.private 1.0

Then I have to create the following QML type:

WindowGestureOverride {
    id: gestureOverride
    active: true
    on_WindowChanged: {
        console.log("on window changed called")
    }
}

For the gesture handling I can use a PeekFilter in my QML file:

PeekFilter { id: peekFilter

    onGestureCanceled: {
        ...
    }
    onGestureTriggered: {
        ...
    }
    onGestureStarted: {
        ...
    }

    enabled: true
    bottomEnabled: true
    leftEnabled: true
}

Unfortunately I haven't found a solution to overwrite system gestures seletively. I played around with a MouseArea and the active property of the WindowGestureOverride element:

MouseArea {
    id: mouseArea
    anchors.fill: parent
    onEntered: {
        if (mouseY < 5) {
            gestureOverride.active = false
        } 
    }
}

This doesn't work. I assume, that it's too late, that the system recognised the system gesture, if the active property is set to false. Has someone an idea?

Furthermore, I have the following challenges:

  1. How can I access the horizontal position of the swipe, if Wouldlike to offer different bottom up swipes like the top down swipes of Sailfish 3?
  2. How can I capture the swipe gesture, if the keyoard is opened?
edit flag offensive delete publish link more
2

answered 2019-01-01 13:57:27 +0300

jsommer gravatar image

updated 2019-01-02 10:17:06 +0300

I could make one step forward but I couldn't find a solution, yet. There is no QML API for gesture event, so I need to write my own evaluation of mouse events:

MouseArea {
    id: mouseArea
    enabled: true
    anchors.fill: parent
    propagateComposedEvents: true

    property var position : {"x":0, "y":x}

    onEntered: {
        position.x = mouseX
        position.y = mouseY
    }
    onMouseXChanged: {
        if (mouseX - position.x > 100 && Math.abs(mouseY - position.y) < 10) {
            // do something for a right swipe
        } else if (position.x - mouseX > 100 && Math.abs(mouseY - position.y) < 10) {
            // do something for a left swipe
        }
    }
}

I placed tested element under a SilicaListView and directly under a Page. Unfortunately the MouseArea blocks all events for the underlying elements like the list items, although I have set the propagateComposedEvents property to true. I played with Connections and was able to capture the onClick: signal, but I couldn't evaluate, wether the mouse loication is in the a specific sub element, because mouseX and elementId.x is 0.

It will be even more tricky to forward selected edge swipe events to system edge swype events. Any solution?

Here is my page structure:

Page {
    ...
    SilicaListView {
        PullDownMenu {
             ...
        }
        headser: Column {
            ...
        }
        ...
        MouseArea {
            ...
        }
    }
    ...
}
edit flag offensive delete publish link more

Comments

to propagate events to underlying components, set mouse.accepted to false in event handlers

Aldrog ( 2019-01-03 16:09:35 +0300 )edit

Where do I have to set mouse.accepted = false in the forground element? I tried the following approach:

MouseArea {
    ...
    onClicked: {
        mouse.accepted = false;
    }
    ...
}

This doesn'r work. As a workaround I use a Connections-Element in the underlying element:

Connections {
    target: mouseArea
    onClicked: {
        textArea.forceActiveFocus()
    }
}

This doesn't help for complex gestures, in particular system gestures.

jsommer ( 2019-01-05 22:40:27 +0300 )edit
Login/Signup to Answer

Question tools

Follow
5 followers

Stats

Asked: 2018-12-29 19:22:24 +0300

Seen: 973 times

Last updated: Mar 09 '19