Hello! Last week I wrote about how
to start developing for the Sailfish OS mobile platform . Today I would like to talk about the life cycle of Sailfish applications, about creating and managing application pages, as well as about some specific features of mobile applications that should be considered when developing for Sailfish OS, in particular, device orientation management.
The SailfishOS SDK (the work with which was described in the previous article) includes the Sailfish Silica - QML module used to create Sailfish applications. This module contains QML components that look and manage in accordance with the standards of the application for Sailfish. Among other things, Sailfish Silica also contains tools for creating specific elements of Sailfish applications, such as, for example,
Cover Page , which were slightly affected in the
previous article . In order to use the Sailfish Silica module and its tools and components, you simply need to import this module into the QML files of the application code. This will be shown in the example a little later.
Applicationwindow
QML is the core of any Sailfish application, which is the
ApplicationWindow component, which describes the application window and contains the application user interface and is generally the primary and mandatory input point for the Sailfish application. The application screens are implemented using the
Page component. At the same time,
ApplicationWindow contains the
initialPage property, which allows you to set the initial screen of the application. Thus, the minimal application for the Sailfish platform will look like this:
import QtQuick 2.2 import Sailfish.Silica 1.0 ApplicationWindow { initialPage: Component { Page { Label { text: ", !" anchors.centerIn: parent } } } }
This application will display one simple page with the words
Hi, Habr! in the middle. It is not necessary to describe the page itself directly in the description of the property, you can simply pass there the page id or the file URL where the page is described.
Page stack
In addition to the initial page,
ApplicationWindow also contains the
pageStack property, which contains the
Page Stack component, which allows you to control the stack of screens (or pages) of an application. In the example above, the
Page Stack consists of just one page that was put on this stack using the
initialPage property. You can add a page to the top of the page stack (and, accordingly, display it on the screen) using the
push () method, passing as an argument the path to the QML file with the page or the id of this page. Let us expand our example by adding a button below the caption, which, when clicked, will take you to the next page (we assume that the code for this page is contained in the
SecondPage.qml file):
ApplicationWindow { initialPage: initialPage Page { id: initialPage Label { id: helloLabel text: ", !" anchors.centerIn: parent } Button { text: "" anchors.top: helloLabel.bottom anchors.horizontalCenter: parent.horizontalCenter onClicked: pageStack.push(Qt.resolvedUrl("SecondPage.qml")) } } }
In the
push () method as well, instead of one page, you can pass an array containing several pages. In this case, all these pages will be added to the stack. This method has two more optional arguments. The first is the page settings, and the second is the type of operation that determines whether to use the animation when moving to the specified page. It can be one of two values:
PageStackAction.Animated or
PageStackAction.Immediate . This argument is also present in all other
Page Stack methods that are responsible for changing the current page (for example, the
pop method, which will be discussed later). By default, all transitions are carried out with animation, which is convenient. If for some reason you do not need animation during the transition, you can call the method as follows:
pageStack.push(Qt.resolvedUrl("SecondPage.qml"), { }, PageStackAction.Immediate)
To return to the previous page, call the
pop () method on the
Page Stack component. This method will remove the topmost page from the stack and, accordingly, go back one page. Optionally, the method can also specify some page that is already on the stack. In this case, the method will remove from the stack all pages located on the stack above the specified one. It is also worth noting that the transition back to the Sailfish OS platform is implemented using a horizontal swipe from the left edge of the screen, however, this functionality is already implemented in Sailfish Silica and the
pop () method is automatically called with this gesture, which is convenient because the developer does not need to attach efforts to implement the standard functionality.
')
In addition to the methods described above, the
Page Stack also provides properties such as
depth (the number of pages in the stack) and
currentPage (current page), as well as methods such as:
- replace () - replaces the current top page on the stack,
- pushAttached () - adds the specified page to the top of the stack, but does not jump to it (the user can go to this page using a horizontal swipe from the right edge of the screen),
- navigateForward () and navigateBack () - navigates to the next or previous page in the stack relative to the current, respectively, without changing the stack itself.
Of course, not all methods and properties of the
Page Stack component are described above. However, I tried to describe the main ones that may be useful in the first place. More information about the component can be found in the
official documentation .
Dialog
The conversations in Sailfish OS are the same pages. However, they are intended to display the user some data with which he may agree or disagree. And he can do it by pressing the buttons, or by swiping to the left (agree) or to the right (refuse). Since the dialogue is a special page, in Sailfish Silica the
Dialog component is “inherited” from the
Page component. Let's replace in the previous example the transition to the next page to show the minimum dialogue. To do this, we describe the dialog in our
ApplicationWindow :
ApplicationWindow { initialPage: initialPage Page { id: initialPage Label { id: helloLabel text: ", !" anchors.centerIn: parent } Button { text: "" anchors.top: helloLabel.bottom anchors.horizontalCenter: parent.horizontalCenter onClicked: pageStack.push(dialog) } } Dialog { id: dialog Label { text: " - " anchors.centerIn: parent } } }
Even the dialogue is shown by adding it to the page stack. If you start the application and click on the button, we will see the following:

As you can see, outwardly, this minimal dialog is no different from a regular page. However, its behavior is different: when you swipe left or right (or click on the white areas in the upper left or lower corner), the dialog closes and the initial page of the application will be shown. In this case, depending on the direction of the svayp, the corresponding dialogue signal (
onRejected or
onAccepted ) will be called. This can be checked by adding signal handlers to the dialog, which will change the text on the main page:
onAccepted: helloLabel.text = "" onRejected: helloLabel.text = ""
Also on the dialogue, using the
DialogHeader component, you
can add the standard “Cancel” and “Accept” buttons at the top of the dialogue. In this case, to display these buttons, simply add an empty component. Optionally, you can also specify the
title property, which will define the text to be located under the buttons. This text is usually used to display the question to the user. Add a
DialogHeader to the dialog from the example above:
Dialog { id: dialog DialogHeader { title: " " } Label { text: " - " anchors.centerIn: parent } onAccepted: helloLabel.text = "" onRejected: helloLabel.text = "" }
Now it looks like this:

It should be noted that when you run the example above, you can see the following warnings:
[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
They have no effect on the functionality, but I could not find the reason for these warnings on the Internet. This seems to be a minor flaw, as Sailfish Silica is still in development. Hopefully, in the future, these shortcomings will be corrected.
Read more about
Dialog in the
official documentation .
Application and Cover Lifecycle
The life cycle of applications for Sailfish OS is quite simple. Since the platform implements full-fledged 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 it is running in active mode (foreground). At the same time, in the active mode, the application is expanded to full screen, while in the background mode, the application is represented by its miniature (called the cover) on the main screen of the system (this was written a little in the
previous article ). You can determine in which state the application is using the
Qt.application.state property. If the application is in the background, this property takes the value
Qt.ApplicationInactive . Otherwise,
Qt.ApplicationActive . The state of the application must be known and used, for example, to stop heavy computational tasks or animations when the application is in the background in order not to waste system resources.
When an application is in a background, its thumbnail is displayed on the main screen. You can describe this cover in the application code using the
Cover component. By default, the application already has a cover, which looks like this:

You can set your cover using the
cover property of the
ApplicationWindow component. Let us redo the example above so that when you click on the buttons in the dialog, the text does not change on the main screen of the application, but on its cover:
ApplicationWindow { initialPage: initialPage cover: cover Page { id: initialPage
Of course, this example is intended only to familiarize readers with the work with the
Cover component. In a real application, the cover represents the application itself on the main screen of the system. Therefore, he must, first of all, present the application so that the user at first glance can find out that this is a miniature of this particular application. Secondly, the cover should contain the minimum amount of the most important information, since the user can see all the details by opening the application itself. And finally, thirdly, as shown in the example above, the cover of the application should change, following the state of the application itself and its data.
Sailfish OS also allows cover to perform demanding tasks: animations, calculations, etc. However, it is worth noting that since an application can be in the background along with other applications and its thumbnail is displayed along with the rest, these tasks should not load the system constantly and should be performed periodically. For example, a weather application should update its cover only when new weather data comes from the server. In addition, you should not perform such tasks when the thumbnail is not visible to the user (for example, when the main screen is closed). To do this, you can use the
status property, which takes one of the following values:
- Cover.Inactive - the miniature is not visible and the user cannot interact with it,
- Cover.Active - the thumbnail is visible and the user can interact with it,
- Cover.Activating - the thumbnail changes to Cover.Active status,
- Cover.Deactivating - the thumbnail changes to Cover.Inactive status.
In addition, the cover can also provide the user with the ability to control the application directly from the thumbnail itself. To do this, using the
CoverActionList component, inside which
CoverAction components are
defined , you can add buttons to the thumbnail. For example, for a music player, these can be the stop and playback buttons for a song, as well as the buttons for moving to the next or previous track. Add a control button to the thumbnail from our example. This button will change the inscription on our miniature:
Cover { id: cover transparent: true Label { id: coverLabel text: ", !" anchors.centerIn: parent } CoverActionList { CoverAction { iconSource: "image://theme/icon-cover-next" onTriggered: coverLabel.text = "!" } } }
More information about the
Cover can be found in the
official documentation .
Device orientation
Like other mobile devices, devices on the Sailfish OS platform support two possible screen orientations: portrait and landscape. To find out the current device orientation, you can use the
isPortrait and
isLandscape properties of the
Page component, or the
orientation property, which takes one of the following values:
Orientation.Portrait ,
Orientation.Landscape ,
Orientation.PortraitInverted or
Orientation.LandscapeInverted . Also, if it is important to check for example that the device is in portrait orientation, and whether it is inverted or not is not important, then you can compare the value of the
orientation property with the
Orientation.PortraitMask mask. For landscape mode, there is a similar
Orientation.LandscapeMask mask.
If you want the application to work only in certain orientations, then you can use the
allowedOrientations property of the
ApplicationWindow component, which can indicate in what orientations the application should work. As values, you can specify the same values ​​as the
orientation property, as well as the
Orientation.LandscapeMask ,
Orientation.PortraitMask or
Orientation.All masks. The default value of the
allowedOrientations property depends on the specific device, so if it is important for an application that it should work in certain orientations (or in any), then it is better to indicate this explicitly. In addition, this property can also be specified for the
Page component, then the rule of allowed orientations will be applied only to a specific page.
That's all. However, I would like to note that in spite of the fact that in the examples of this article all the code was described in one file, when writing real applications it is best to describe each page and cover in a separate QML file. This will speed up the launch of the application, as it will prevent the compilation of all QML components when the application is started.
In the next article I will talk about the other components that make up Sailfish Silica.
Article author: Denis Laure