Developing for SailfishOS: the basics

Hello! Last week I wrote about how to start develop for the mobile platform Sailfish OS. Today I would like to tell you about the life cycle of Sailfish apps, create application pages and manage them and about some specifics of mobile apps to consider when developing for Sailfish OS, in particular the control of the orientation of the device.

The composition of the SailfishOS SDK (which was described in the last article) is Silica Sailfish — QML module used to create Sailfish apps. This module provides QML components that look and are managed in accordance with the standards of applications to Sailfish. In addition, Sailfish Silica also contains tools for creating custom elements Sailfish applications, such as, for example, Cover Page, which was slightly raised in the last article. In order to use the Sailfish Silica module and its tools and components, you just need to import this module in QML files of the application code. It will be shown in the example later.

ApplicationWindow


Sailfish QML core of any application is the ApplicationWindow, which describes the application window and contains the application's user interface and in General is the main and mandatory entry point download Sailfish apps. The screens of the application is implemented using the component Page. Thus ApplicationWindow contains the property initialPage allowing to set the initial screen of the application. Thus the minimum application for the platform Sailfish will look like the following:
the
import QtQuick 2.2
import Sailfish.Silica 1.0

ApplicationWindow {
initialPage: Component {
Page {
Label {
text: "Hello, Habr!"
anchors.centerIn: parent
}
}
}
}

This application will display a simple page that says Hello, Habr! in the middle. Do not have to describe the page itself right in the description of the property, you can just pass back the id of a page or the URL of the file which describes the page.

Page Stack


In addition to home page ApplicationWindow also contains the property pageStack component containing a Page Stack that allows you to manage a stack of screens (or pages) of the application. In the example above, Page Stack consists of only one page, which was put on the stack by using the properties of initialPage. Add a page to the top of the stack of pages (and therefore display it on the screen), you can use the method push(), passing it as argument the path to the QML file with the page id of this page. Extend our example by adding an inscription under the button, when clicked, will go to the next page (we assume that the source of this page contains in the file SecondPage.qml):
the
ApplicationWindow {
initialPage: initialPage
Page {
id: initialPage
Label {
id: helloLabel
text: "Hello, Habr!"
anchors.centerIn: parent
}
Button {
text: "Next"
anchors.top: helloLabel.bottom
anchors.horizontalCenter: parent.horizontalCenter
onClicked: pageStack.push(Qt.resolvedUrl("SecondPage.qml"))
}
}
}

In the method of push() as well, instead of one page, you can pass an array that contains multiple pages. In this case, all these pages will be added to the stack. This method has two more optional arguments. The first is the settings page, and the second — type operation that specifies whether to use animation when switching to the specified page. It can be one of two values: PageStackAction.Animated or PageStackAction.Immediate. This argument is also present in all other methods, Page Stack, which are responsible for the change of the current page (for example, the method pop, which will be discussed later). By default, all transitions are animated, which is convenient. If for some reason the animation when switching is not needed, you can call the method as follows:

In order to return to the previous page you need on the component Page Stack call method pop(). This method will remove from the stack the top-most page and, accordingly, will be taken to a page ago. Optional method you can also specify a certain page that is already on the stack. In this case, the method will remove from the stack all the pages located on the stack above that. Here it is also worth noting that the transition back to the platform Sailfish OS is implemented using a horizontal swipe from the left edge of the screen, but in Sailfish Silica this functionality is already implemented in the gesture method is automatically called pop(), which is convenient because the developer does not need to exert efforts for the implementation of standard functionality.

In addition to the above methods Page Stack also provides properties such as depth (the number of pages in the stack) and currentPage (current page), and techniques such as:
the

    replace() — replaces the current top page in the stack

    pushAttached() — adds the specified page to the top of the stack, but does not transition to it (the user can navigate to this page using the horizontal swipe from the right edge of the screen)

    navigateForward() and navigateBack() — making the transition to, respectively, the next or previous page in the stack relative to the current, while altering the stack itself.


Of course, the above described methods and properties of the component Page Stack. However, the basic that can be useful in the first place, I tried to describe. Read more about the component can be read in official documentation.

Dialog


Dialogs in Sailfish OS represent the same page. However, they are intended to display the user some data with which he can agree or disagree. And he can hold down the button and swipe to the left (accept) or right (to refuse). Since dialogue is a particular page in the Sailfish Silica component Dialog "inherited" from the component Page. Replace in the previous example, go to the next page to show that the minimum of dialogue. To do this, we will describe the dialogue in our ApplicationWindow:
the
ApplicationWindow {
initialPage: initialPage
Page {
id: initialPage
Label {
id: helloLabel
text: "Hello, Habr!"
anchors.centerIn: parent
}
Button {
text: "Next"
anchors.top: helloLabel.bottom
anchors.horizontalCenter: parent.horizontalCenter
onClicked: pageStack.push(dialog)
}
}
Dialog {
id: dialog
Label {
text: "I'm a dialog"
anchors.centerIn: parent
}
}
}

Even the dialog by adding it to the stack of pages. If you run the app and click on the button, we see the following:

As you can see, externally the minimal dialogue is no different from a normal page. However, its behavior is different: when you swipe to the left or right (or clicking on the white area in the upper left or lower right corner) the dialog closes and shows the start page of the application. Thus, depending on the swipe direction will be called a signal corresponding to the dialogue (onRejected or onAccepted). You can check this by adding in dialogue data processors signals that will change the text on the main page:
the
onAccepted: helloLabel.text = "Agreed"
onRejected: helloLabel.text = "Refused"

Also on the dialog, you can use the component DialogHeader add standard buttons "Cancel" and "Accept" at the top. At the same time to display these controls, simply add an empty component. Optionally you can also specify a property title, which will determine the text that will be located under the buttons. This text is typically used to display questions to the user. Add DialogHeader in the dialogue in the example above:
the
Dialog {
id: dialog
DialogHeader {
title: "Simple dialog"

Label {
text: "I'm a dialog"
anchors.centerIn: parent
}
onAccepted: helloLabel.text = "Agreed"
onRejected: helloLabel.text = "Refused"
}

Now it looks like this:


It should be noted that when you run the example above you can see the following warnings:
the
[W] unknown:189 - file:///usr/lib/qt5/qml/Sailfish/Silica/DialogHeader.qml:189: TypeError: Cannot read property 'backIndicatorDown' of null
[W] unknown:194 - file:///usr/lib/qt5/qml/Sailfish/Silica/DialogHeader.qml:194: TypeError: Cannot read property 'backIndicatorDown' of null
[W] unknown:247 - file:///usr/lib/qt5/qml/Sailfish/Silica/DialogHeader.qml:247: TypeError: Cannot read property 'forwardIndicatorDown' of null
[W] unknown:242 - file:///usr/lib/qt5/qml/Sailfish/Silica/DialogHeader.qml:242: TypeError: Cannot read property 'forwardIndicatorDown' of null

On functionality they do not affect, but on the Internet to find the cause of these warnings I failed. It seems that this small glitch, as the Sailfish Silica is still in development. Let's hope that in the future these shortcomings will be corrected.

Read more about Dialog can be read official documentation.

application Lifecycle and Cover


The life cycle of apps for Sailfish OS is very simple. Since the platform implements a full multi-tasking, the application can be in one of three States: either it is not running at all or it works in the background (background), or in the active mode (foreground). While in active mode, the application maximized, while in the background the app is represented by its own thumbnail (called a cover) on the main screen of the system (this was written in a little previous article). To determine in what state your application is in you can use the properties Qt.application.state. If the app is in the background, this property is set to Qt.ApplicationInactive. Otherwise, Qt.ApplicationАctive. The application state must be known and used, for example, to stop heavy computing tasks or animations when the app is in the background, to avoid wasting system resources.

When the app is in the background, the main screen displays its thumbnail — cover. To describe this cover in your application code by using the component's Cover. By default, the app is already installed cover, which looks as follows:

To set your cover you can use the properties cover component ApplicationWindow. Will rework the example above so that when pressing the buttons in the dialog to change the text not on the main screen of the application, and on its cover:
the
ApplicationWindow {
initialPage: initialPage
cover: cover
Page {
id: initialPage
// Description of main page...
}
Cover {
id: cover
transparent: true
Label {
id: coverLabel
text: "Hello, Habr!"
anchors.centerIn: parent
}
}
Dialog {
id: dialog
DialogHeader {
title: "Simple dialog"
}
Label {
text: "I'm a dialog"
anchors.centerIn: parent
}
onAccepted: coverLabel.text = "Agreed"
onRejected: coverLabel.text = "Refused"
}
}

Of course, this example is intended only to acquaint readers with the work of the component Cover. In a real application cover represents the app on the main screen of the system. Therefore, it needs, firstly, to present the application to the user at the first glance would know that it is a miniature of this particular application. Secondly, the cover should contain the minimum number of the most important information because all the details the user can see by opening the app itself. And finally, third, as shown in the example above, cover of the application should change, after the state of the application and its data.

Sailfish OS also allows the cover to perform intensive tasks such as animations, calculations etc., However, it is worth noting that since the app is in the background with other applications and its thumbnail displayed along with the other, then these tasks should not burden the system constantly and will be executed periodically. For example, a weather app should update your cover only when the servers come new weather data. In addition, it is not necessary to perform such tasks, when the thumbnail image is not visible to the user (for example, closed when the main screen). You can use the property status, which takes one of the following values:

Cover.Is Inactive — the thumbnail is not visible and the user cannot interact with,

Cover.Active — the thumbnail is visible and the user can interact with,

Cover.Activating — a thumbnail switches to the status Cover.Active,

Cover.Deactivating — a thumbnail switches to the status Cover.Is Inactive.

In addition cover may provide the user the ability to control the application directly from the thumbnail. For this component CoverActionList, inside of which are determined by the components CoverAction, you can add thumbnail buttons. For example, for a music player that can be the stop button and song playback, as well as the buttons move to next or previous track. Add a control button on the thumbnail of our example. This button will change the inscription on our miniature:
the

Cover {
id: cover
transparent: true
Label {
id: coverLabel
text: "Hello, Habr!"
anchors.centerIn: parent
}
CoverActionList {
CoverAction {
iconSource: "image://theme/icon-cover-next"
onTriggered: coverLabel.text = "Next!"
}
}
}

Read more about Cover can be read official documentation.

device Orientation


Like other mobile devices on the platform Sailfish OS supports two possible screen orientations: portrait and landscape. In order to know the current orientation of the device, you can use the properties isPortrait and isLandscape component Page or the property orientation, which takes one of the following values: Orientation.Portrait, Orientation.Landscape, Orientation.PortraitInverted or Orientation.LandscapeInverted. Also, if for example it is important to check that the device is in portrait orientation, and inverted it or not, it is possible to compare the value of the property orientation with a netmask Orientation.PortraitMask. For landscape mode there is a similar mask Orientation.LandscapeMask.

If you want the application to work only in certain orientations, you can use the property allowedOrientations component ApplicationWindow, which can specify the orientations the app should work. As values you can specify the same value that the property returns orientation and mask Orientation.LandscapeMask, Orientation.PortraitMask or Orientation.All. The default value of the property allowedOrientations depends on the specific device, so if the application is important that it should work in certain orientations (or any), it is better to specify it explicitly. In addition, this property you can specify the component Page, then the rule of the allowed orientations will apply only to a specific page.

That's about it. However, I would like to note that despite the fact that the examples in this article all the code has been described in a single file, when writing real applications it is best to describe each page and cover in a separate QML file. This will speed up the application startup, since it will prevent the compilation of all QML components when the application starts.

In the next article I will talk about other components included in the Sailfish Silica.

Author: Laura Dennis
Article based on information from habrahabr.ru

Популярные сообщения из этого блога

Approval of WSUS updates: import, export, copy

Kaspersky Security Center — the fight for automation

The Hilbert curve vs. Z-order