Awesome
<!-- SPDX-FileCopyrightText: 2021-2023 Mirian Margiani SPDX-License-Identifier: GFDL-1.3-or-later -->Opal
Opal is a collection of pretty QML components for SailfishOS, building on top of Sailfish's Silica components. It provides ready-made components, examples, snippets, recipes, and resources for building more sailfishy Sailfish apps.
This repository contains documentation, snippets, and development tools.
If you want to create new applications using Opal, follow the steps below. Opal is a library for developers. As an end-user you should not have to do anything.
Project status
Opal is ready for production. That being said, Opal is not yet very mature and the ecosystem still has to grow.
Notably still missing:
- resources modules (i.e. extra icons etc.) are not yet properly supported
- plugins (i.e. modules with parts written in C++) are not yet supported
- code documentation is only available in QtCreator but should be hosted online
Contents <a id='opal-list'/>
Snippets / development tools <a id='snippets'/>
- cached-defines.pri: A helper and recipe for passing build options from YAML to QML.
- merge-translations.sh: A script for merging Opal translations into your app's
ts
files. - render-icons.sh: A script for rendering and optimizing SVG icons during iterative development.
All snippets are released into the public domain, unless otherwise specified. Please refer to the respective snippet files.
Modules <a id='modules'/>
Note that modules generally are licensed under the GNU GPL. However, all Opal modules have their own licensing. Please refer to the respective repositories for details.
To get an overview of the currently available modules, install the gallery app from Jolla's Harbour store or from OpenRepos. You can also browse the repositories here.
Stable
- <a id='module-about'/>Opal.About: A simple and flexible "About" page supporting license info, contributors, donations, etc.
- <a id='module-supportme'/>Opal.SupportMe: A dialog asking for support that is shown when a user has used your Sailfish app for some time.
- <a id='module-delegates'/>Opal.Delegates: List items that can show multiple lines of text and icons by default.
- <a id='module-smartscrollbar'/>Opal.SmartScrollbar: A Harbour-compatible smart scrollbar for easier access in long lists.
- <a id='module-menuswitch'/>Opal.MenuSwitch: A toggle switch for Sailfish menus.
- <a id='module-infocombo'/>Opal.InfoCombo: A combo box that can show detailed descriptions of all menu items.
- <a id='module-combodata'/>Opal.ComboData: An extension for combo boxes to access the current value instead of the label.
- <a id='module-linkhandler'/>Opal.LinkHandler: A link handler to open or copy external links.
In development
- <a id='module-hints'/>Opal.Hints: Interaction hints helping users discover features.
- <a id='module-tabbar'/>Opal.TabBar: An app-wide tab bar using icons with optional texts, and improved support for landscape layouts. Not yet properly integrated and still lives in its old repository.
Using Opal <a id='using-opal'/>
Follow these steps to include Opal modules in your project:
-
Fetch the latest Opal release bundle.
-
Extract opal-merge-translations.sh to
<project>/libs
. -
Fetch the module bundles you want to use and extract the
libs
andqml
folders in your project root. (For example, ready-made translations should end up inharbour-my-app/libs/opal-translations/
, while QML files should be inharbour-my-app/qml/modules/Opal/MyModule
.) -
You can now use the modules. For the About page component you would have to write in QML (e.g. at
qml/pages/AboutPage.qml
):import "../modules/Opal/About"
To use default attributions, you would have to import them on the “About” page like this:
import "../modules/Opal/Attributions"
Note: this is a path relative to the QML file you are working with. The "../" in this example assumes that you are, for example, editing the page
harbour-my-app/qml/pages/AboutPage.qml
. -
Configure your
spec
file to be Harbour-compatible (cf. Harbour FAQ #2.6.0). Add the following section to youryaml
file (from which thespec
file is generated). If there already is aMacros:
section, simply add the contents below.Macros: - __provides_exclude_from;^%{_datadir}/.*$
Alternative: the Harbour FAQ #2.6.0 recommends adding a line directly to the
spec
file. You would have to re-add this line every time after changing the YAML file, though. This is due to a bug in the Sailfish SDK.# >> macros %define __provides_exclude_from ^%{_datadir}/.*$ # << macros
-
Merge shipped translations with your local translations. If you have Qt's
lconvert
installed, you can simply run this code:$ cd libs $ ./opal-merge-translations ../translations
Otherwise, run it inside an
sfdk
target, so you will need to run something like the following (replacingSailfishOS-4.5.0.16EA-aarch64
with one of your targets).$ cd libs $ sfdk engine exec sb2 -t SailfishOS-4.5.0.16EA-aarch64 \ ./opal-merge-translations.sh ../translations
Note: run
sfdk --help
to get more information about the tool. -
Add docs and translations to
.gitignore
. They have been merged with your main translations.libs/opal-translations libs/opal-docs
-
Add proper attribution, e.g. to your “About” page. Opal modules provide QML elements that can be used directly in Opal.About: import
../modules/Opal/Attributions
, then addOpal[MyModule]Attribution {}
to theattributions
list property of the “About” page.
After the initial setup you can easily add additional modules by simply extracting QML sources, docs, and translations to the respective directories.
Dot-notation (optional)
Additional steps are required to be able to import modules using the dot-notation.
- Register
qml/modules
as QML import path. The code below is fine for new projects. This is not necessary for QML-only projects using QML-only modules.
//// in src/harbour-myproject.cpp:
int main(int argc, char *argv[])
{
QScopedPointer<QGuiApplication> app(SailfishApp::application(argc, argv));
app->setOrganizationName("harbour-myapp"); // needed for Sailjail
app->setApplicationName("harbour-myapp");
QScopedPointer<QQuickView> view(SailfishApp::createView());
// add module search path so Opal modules can be found
view->engine()->addImportPath(SailfishApp::pathTo("qml/modules").toString());
view->setSource(SailfishApp::pathToMainQml());
view->show();
return app->exec();
}
-
If everything is set up correctly, you can now use Opal by importing the modules via the dot-notation. For the “About” page component you would have to write in QML:
import Opal.About 1.0
Note: ready-made attributions in
qml/modules/Opal/Attributions
must be imported by path due to technical limitations of Qt's module system. Import them like this:import "../modules/Opal/Attributions"
Sailfish SDK (Qt Creator)
If auto-completion does not work, add qml/modules
to the IDE's module
search path. Add this line to your project's .pro
file:
QML_IMPORT_PATH += qml/modules
Apps using Opal
Please contact us if your app uses Opal so we can include it in this list!
Project | Modules |
---|---|
Opal Gallery: gallery app showcasing all modules | all modules (with examples) and snippets |
File Browser: fully-fledged file manager for Sailfish OS | Opal.About, Opal.SupportMe, Opal.InfoCombo, Opal.ComboData, snippets |
Expenditure: group travel finance helper for splitting bills | Opal.About, Opal.SupportMe, Opal.Delegates, Opal.SmartScrollbar, Opal.ComboData, snippets |
To-do List: focused to-do list app | Opal.About, <!--[Opal.TabBar](#module-tabbar),--> snippets |
Captain's Log: simple diary app | Opal.About, Opal.SupportMe, Opal.InfoCombo, Opal.ComboData, Opal.LinkHandler, snippets |
Parking Chaos: "Traffic Jam" game | Opal.About, snippets |
Laundry List: laundry management helper | Opal.About, snippets |
Minidoro: Pomodoro technique timer for productivity | Opal.About, Opal.LinkHandler, snippets |
Meteo: weather forecasts | sf-about-page |
Jammy: Jamendo client featuring advanced search | sf-about-page |
Directory: search the national phone book | Opal.About |
Dictionary: to be merged upstream into Wunderfitz | sf-docked-tab-bar |
Sailtrix: Matrix client | sf-docked-tab-bar |
Olive goes shopping: shopping list app | sf-docked-tab-bar |
Skruuvi: native reader for Ruuvi sensors | Opal.About |
Screen Time: track your screen time usage on Sailfish OS | Opal.About |
Outpost: an unofficial app for InPost | Opal.About |
SailDiscord: an unofficial client app for Discord | Opal.About |
Developing Opal <a id='developing-opal'/>
All modules live in their own repositories.
Useful tools for developing Opal can be found in the opal-development directory.
Licensing
All contributions to Opal must be licensed under Free Software licenses compatible with the GNU GPL v3. Apart from that, you are free to choose a license of your liking from the SPDX license list for your new contents.
Important: make sure your contributions are REUSE compliant. This makes it much easier to reuse them in other projects, to write proper attributions, and to find incompatibilities.
Translating modules
Some modules provide their own translations that can be used by other apps.
To use packaged translations in your project, follow the main documentation for using Opal modules here.
You can also contribute translations, so that all apps using Opal can benefit from it. Translations are managed using Weblate.
Please prefer Weblate over pull requests (which are still welcome, of course).
Adding snippets
- Add a new snippet file in the [snippets] diretory
- Add a Markdown file for documentation with the same name
- Add an entry in the list of snippets above
Coding conventions: please use Shellcheck when writing Bash scripts. Read the documentation on common Bash pitfalls and avoid them at all costs. Opal snippets are intended to be run on recent versions of GNU Bash (> 5.0) unless explicitly documented otherwise.
Adding new modules
-
Copy the Opal module template repository, and initialize a new repository for your module:
$ git clone https://github.com/Pretty-SFOS/opal-module-template mymodule $ cd mymodule $ rm -rf .git $ git init
-
Run the setup script to configure the new module:
$ ./setup.sh --help $ ./setup.sh mymodule MyModule "Jane Doe" "QML module for SOMETHING in Sailfish apps" "This module provides SOMETHING to DO SOMETHING."
-
Follow the instructions in the
README.md
file.
Once these basics are setup, you can use the Opal Gallery app to test and develop your module.
-
Clone the gallery app next to the
opal
directory:$ cd /path/to/my/dev/stuff/ $ git clone https://github.com/Pretty-SFOS/opal-gallery opal-gallery
-
Register your module in the gallery by adding it to the
cQML_MODULES
array infetch-modules.sh
. Note: remove all other modules from the array, unless you have cloned their repositories.# name of your module's directory without the "opal-" prefix cQML_MODULES=(mymodule)
-
Run
fetch-modules.sh
to include all registered modules in the gallery app. -
Open the gallery app project in the Sailfish IDE (QtCreator) and edit your module in
qml/modules/Opal/MyModule
. -
Open
qml/harbour-opal-gallery.qml
and set thedevelJumpToModule
property to your module's name. -
Create one or more example pages for the new module. The main page must be
doc/gallery.qml
. Extra pages can be added asdoc/gallery/*.qml
. See the module metadata file for details. Edit this example page in the gallery app inqml/module-pages/opal-<mymodule>/gallery.qml
. -
Last but not least, add an entry in the list of modules in Opal's README.md file.
Translations: Make sure to use qsTranslate("Opal.<Module>", "string")
instead of
qsTr("string")
for all translations. Otherwise merged translations would
clutter a user's app translation files.
Coding conventions: please follow the Sailfish coding conventions and the Qt coding conventions where possible. Read the documentation on common pitfalls in Sailfish app development and avoid them unless you have a very good reason.
Hint: use the Silica cheatsheet and the Theme cheatsheet.
Adding plugins
TBD.
Plugins require additional build processes which are not yet properly supported. They have to be built using the Sailfish IDE, pre-packaged, and then included in target apps.
Handling should be identical to QML-only modules.
Coding conventions: please follow the Sailfish coding conventions where possible.
Adding resources
TBD.
- Create a new repository named
opal-res-<...>
- Create the same structure as in
opal-res-extra-icons
(changing the relevant parts) - TBD: showcase in gallery app
- TBD: add to wiki
Licenses
All Opal modules have their own licensing. Please refer to the respective repositories.
All snippets are released in the public domain, unless otherwise specified. Please refer to the respective snippet files.
All documentation is released under the terms of the GFDL-1.3-or-later.
Copyright (C) Mirian Margiani
Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.3
or any later version published by the Free Software Foundation;
with the Invariant Sections being [none yet], with the Front-Cover Texts
being [none yet], and with the Back-Cover Texts being [none yet].
You should have received a copy of the GNU Free Documentation License
along with this document. If not, see <http://www.gnu.org/licenses/>.