📜 ⬆️ ⬇️

Development for SailfishOS: Basics

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:

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 //    ... } Cover { id: cover transparent: true Label { id: coverLabel text: ", !" anchors.centerIn: parent } } Dialog { id: dialog DialogHeader { title: " " } Label { text: " - " anchors.centerIn: parent } onAccepted: coverLabel.text = "" onRejected: coverLabel.text = "" } } 

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:


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

Source: https://habr.com/ru/post/306188/


All Articles