- What is QtAseman?
- New in QtAseman 3.1.x
- How to Install
- How to Build
- How to create a QML application using QtAseman
- QtAseman QML modules
- Documents
- Donation
QtAseman is a set of tools, design patterns and architectures that we have developed over the years in various projects for wide range of uses. Now, with it's proven stability, we have decided to release this collection with the name QtAseman as an Open Source and Free tool under the LGPLv3 license.
Some main features to use on QML are:
- Viewport tools that provides unique page manager system (page, popup, stack, dialog and ...)
- Gestures for viewports
- Transparent statusbar and optional navigation bar on mobile devices
- Some extra Qml controls components like Drawer, Header, TextField, CircularProgressBar and ...
- BackHandler system
- Font awesome and Material icons fonts
- VideoPlayer component
- Some graphical components like shadows for easy to use and better experiance
- Network and Http Request handler
- Models and Abstract models with better experience
- Encrypt/Decrypt tools
- Qt/C++ Like Hash, Map and List objects
- Tools to get more device infos like deviceId, density, keyboard height, statusBar height and ...
- Translation manager tools
- Settings manager
- Some other tools like file read/write methods, type convert methods and ...
- Process executer tools from QML
- QtAseman's Control Beta. It's a simple example:
import QtQuick 2.15
import AsemanQml.Controls.Beta 3.0
import AsemanQml.MaterialIcons 2.0
Window {
title: qsTr("Hello World")
Style.primaryColor: "#3f51b5"
Style.primaryTextColor: "#fff"
Page {
id: page
anchors.fill: parent
title: "Home"
header: Header {
width: parent.width
}
Button {
id: btn
anchors.centerIn: parent
highlighted: true
icon: MaterialIcons.mdi_dialpad
text: "Test Page"
onClicked: test_stack.open()
}
}
StackPage {
id: test_stack
Page {
id: testStack
header: Header {
height: 50
width: parent.width
}
Button {
anchors.centerIn: parent
highlighted: true
icon: MaterialIcons.mdi_chevron_left
text: "Back"
onClicked: test_stack.close()
}
}
}
}
Currently binary packages only available on the ubuntu (launchpad) repositories. To install it on the ubuntu 20.04 LTS:
sudo add-apt-repository ppa:aseman/qt-modules
sudo apt install qt5aseman
and to install development files install qt5aseman-dev
package.
on Arch you can use AUR (Thanks molaeiali):
yay -S qt-aseman
QtAseman uses standard Qt module mechanisms and it only depends on Qt libraries. Therefor it's quite easy to build on all platforms. Just clone it and build it easily:
git clone https://github.com/Aseman-Land/QtAseman.git --recursive
cd QtAseman
mkdir build && cd build
qmake -r ..
make -j2
make install
The easiest way to build is to open it using QtCreator and click on the build icon :)
Afterwards just run make install
command to install it in the Qt location.
It will install automatically on Linux based operating systems.
For other Operating systems, to install QtCreator's wizards, Just copy src/wizards/qtcreator/qtasemanapplication/
directory to share/qtcreator/templates/wizards/projects/
directory of the QtCreator.
One of the main assets of QtAseman is that you can add it to your project without any extra change to the standard structure of the default QML app.
So To create an application using QtAseman, Just create a new QML project in your QtCreator and add AsemanQML module to the project. Now you can use all QtAseman components:
import AsemanQml.Controls 2.0
import QtQuick.Controls 2.12
AsemanWindow {
visible: true
width: 480
height: 720
title: qsTr("QtAseman Example")
Label {
anchors.centerIn: parent
text: "Hello World! :)"
}
}
If you wish to change any application attribute like applicationName or applicationOrganization you can create an AsemanApp
object in the parent of AsemanWindow
. Although it's completely optional and you can ignore it.
import AsemanQml.Controls 2.0
AsemanApplication {
id: app
applicationAbout: "QtAseman Application"
applicationDisplayName: "QtAseman"
applicationId: "be2a1f0c-34aa-44ed-8e65-4b1720e560b8"
organizationDomain: "aseman.io"
AsemanWindow {
visible: true
width: 480
height: 720
}
}
We suggest you to also create an AsemanApplication object, because QtAseman handles config file paths better while this attributes is set.
Note: In order to make all modules work correctly on android devices you must replace io.aseman.android.AsemanApplication
and io.aseman.android.AsemanActivity
with Qt's values in the android manifest file.
There are many modules and components in QtAseman that will help you create applications without use of any extra C++ code. Also QtAseman offers a great software architecture for each module that makes development much more easier and faster.
AsemanQml.Base module provides many base and core modules for your application. For example modules like Device infos, Desktop functions tools, data type converters, lists, hashes and etc. are placed in Base module.
here is one of the main uses of Base module:
import AsemanQml.Controls 2.0
import AsemanQml.Base 2.0
AsemanWindow {
visible: true
width: 480
height: 720
title: qsTr("QtAseman Example")
Rectangle {
height: Devices.statusBarHeight
width: parent.width
color: "blue"
}
}
QtAseman makes mobile status bars transparent by default and Devices.statusBarHeight
returns the status bar height of the device. The above example makes the status bar color blue. If there is no status bar on the device (like desktop operation systems) it returns zero as the result.
You can get other useful values like screen density, suggested font density, main OS folder locations, platform details, device type and etc. using Devices
component.
Also there is Tools
component that provides some extra tools for applications, like methods to read or write to/from files or methods to convert json to variant map or convert url to local path and etc.
For example below codes create sha256 hash:
var sha = Tools.hash("12345", Tools.Sha256);
Or below codes read text from file:
var text = Tools.readText("/home/bardia/file.txt");
There is also a Process
component that runs processes or a great back handler component named BackHandler
.
BackHandler
component provides back mechanism for your application. It's simple and easy to work with, plus all components of QtAseman support it by default, therefore it handles back actions automatically without the direct interference of developer.
Below example shows you how to use BackHandler
component in your code:
Button {
anchors.centerIn: parent
text: "Show"
onClicked: subRect.visible = true
}
Rectangle {
id: subRect
anchors.fill: parent
visible: false
onVisibleChanged: {
if (visible)
BackHandler.pushHandler(subRect, function(){ subRect.visible = false })
else
BackHandler.removeHandler(subRect)
}
Button {
anchors.centerIn: parent
text: "Hide"
onClicked: BackHandler.back()
}
}
Beside clicking on the hide button to trigger back function, you can press Esc button or the physical back button of device. On mobile devices if there is no back function in the BackHandler stack and back() method is called, application will try to quit.
Note: You must use AsemanWindow object to make Esc or Physical back button work.
Creates a settings file in a specific path and stores settings values there:
Settings {
id: settings
category: "General"
source: AsemanApp.homePath + "/ui-settings.ini"
property bool languageInited: false
property int nightMode: 0
property int colorTheme: 0
property int darkColorTheme: 3
}
Every change in setting's property is saved and can be restored within the next load of application.
Translations
and TranslationManager
provide functions and tools to manage translation in your application:
TranslationManager {
id: translationManager
// Finds all lang-*.qm files in the sourceDirectory using three below lines
sourceDirectory: "../translations"
delimiters: "-"
fileName: "lang"
localeName: "fa"
}
Button {
// Everytime translation changed to other language, Every refresher texts
// will refreshed and translated to the new language
text: qsTr("Dismiss") + Translations.refresher
}
It renders every included child item as rounded. For example below code shows an image with rounded corners:
RoundedItem {
width: 100
height: 100
radius: 10
Image {
anchors.fill: parent
source: "image.png"
}
}
DelegateSwitch
provides a component to switch between two or more children components on the fly. For example:
ListView {
model: 20
delegate: DelegateSwitch {
current: model.index % 2
Component {
Rectangle {
width: 100; height: 40
color: "red"
}
}
Component {
Rectangle {
width: 40; height: 40
color: "blue"
}
}
}
}
This example shows red rectangles on even indexes and blue squeres on odd indexes.
To read more about Base module, please read this document.
Controls module provides any control module like QtQuick.Controls. For example It provides AsemanApplication
, AsemanWindow
, SideMenu
, Header
and many other components.
Below example shows a simple usage of the Controls
component.
import QtQuick 2.9
import AsemanQml.Base 2.0
import AsemanQml.Controls 2.0
AsemanWindow {
visible: true
width: 480
height: 720
title: qsTr("Hello World")
Header {
width: parent.width
text: "Hello"
color: "#18f"
}
Drawer {
id: menu
anchors.fill: parent
delegate: Rectangle {
anchors.fill: parent
color: "#333"
}
}
HeaderMenuButton {
id: btn
/*
* If BackHandler stack is not empty, It shows back
* button instead of hamburger btn.
*/
ratio: BackHandler.count? 1 : menu.percent
onClicked: BackHandler.count? BackHandler.back() : menu.show()
}
}
Viewport module provides a new design architecture for applications.
There is a Viewport
component that provides a manage mechanism for your page, popup, dialogs and etc.
Below example shows you the usage of the Viewport
component.
import AsemanQml.Viewport 2.0
/*
* Viewport component manage pages and Way of the they opened.
* Like popups, pages, dialogs or ...
* It also supports BackHandler by default like other QtAseman components
*/
Viewport {
id: viewPort
anchors.fill: parent
mainItem: Page {
// Main/Default Viewport item
anchors.fill: parent
Button {
text: "Open"
anchors.centerIn: parent
// append hiComponent to the viewPort stack and open it as page
// append() returns a refrence to the created ui object.
// Types are: page, activity, popup, dialog, menu and drawer
onClicked: viewPort.append(hiComponent, undefined, "page")
}
}
}
Component {
id: hiComponent
Page {
id: page
anchors.fill: parent
property int cnt
Button {
id: btn
text: "Open " + (page.cnt+1)
anchors.centerIn: parent
// append method could also pass properties to the dest object
onClicked: viewPort.append(hiComponent, {"counter": page.cnt+1}, "popup")
}
}
}
There is also an attached property, you can use to call append function in the Viewport's childeren components:
Viewport.viewport.append(...)
Using ViewportController
components you won't need to create a complicated architecture. It helps you to make your architecture quite easy and dynamic.
Below example shows you how to create UI and open them easily in the apps.
Using this design architecture, you create separated UI files, link them to their specific path and just call them using controllers anywhere in the App.
ViewportController
opens them automatically in the Viewport
.
Viewport {
id: viewPort
anchors.fill: parent
mainItem: Page {
anchors.fill: parent
Button {
text: "Open"
anchors.centerIn: parent
// Trigger the path and open UI item that linked to the path.
// trigger() returns a refrence to the created ui object.
onClicked: controller.trigger("main://test/bardia")
}
}
}
ViewportController {
id: controller
viewport: viewPort
// Define all your UI routes that connect paths to UI components.
ViewportControllerRoute {
route: /main:\/\/test\/.*/
sourceComponent: hiComponent
viewportType: "popup"
}
ViewportControllerRoute {
route: /about:\/\/aseman\/.*/
// You can also use `source` property and pass component's url to it.
sourceComponent: aboutComponent
viewportType: "page"
}
}
Component {
id: hiComponent
Page {
anchors.fill: parent
Button {
text: "About"
anchors.centerIn: parent
/*
* You can also pass properties to object using js map
* or using html query way (about://aseman/test?text=about&color=blue)
*/
onClicked: controller.trigger("about://aseman/test", {"text": "about"})
}
}
}
Component {
id: aboutComponent
Label {
anchors.fill: parent
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
// If you specify a url property, triggered url will put to this property
property string url
// If you specify a properties property, initial properties will put to this property
property variant properties
}
}
There is also an attached property, you can use to call trigger function in the Viewport's childeren components:
MouseArea {
onClicked: Viewport.controller.trigger("about://aseman/test", {"text": "about"})
}
Viewport.controller
method returns first controller of the parent Viewport. If you wish to get all controllers as array, use Viewport.allController
method instead.
Using ViewportType
attached property, you can change some attributes on the current Viewport's type item:
ViewportType.gestureWidth: 10 // Change touch/mouse gesture area's width
ViewportType.touchToClose: false // Disable touch background to close feature
ViewportType.blockBack: true // Disable press back to close feature
ViewportType.open: false // Close current page of the viewport
ViewportType.transformOrigin: Qt.point(10, 20) // Sets transform origin on some types like menu
Network module provides components to send network requests. For Example NetworkRequestManager
and NetworkRequest
could send http requests like post, get, put and etc.
Below example shows you a simple usage of network module.
import AsemanQml.Network 2.0
Button {
text: "Signup"
onClicked: networkManager.post(signInRequest) // get, post, put or ...
}
BusyIndicator { running: signInRequest.refreshing }
NetworkRequestManager { id: networkManager }
NetworkRequest {
id: signInRequest
contentType: NetworkRequest.TypeJson
url: "https://example.com/auth/signIn"
headers: {
"Authorization": "Bearer ...",
}
// Properties will post as json file map
property string username: "test"
property string password: "pass1234"
// If you specified url property with TypeForm, It will send file, Else send it as string
property url filePath
onServerError: ; // server error codes
onClientError: ; // client error codes
onSuccessfull: {
// Response contains response map if it's json
// or if not response text
console.debug(response.token)
}
}
You can create many simple request files in your project and every time you need them, just send them to the server using NetworkRequestManager and get your response.
Models module provide some ready to use models like CountriesModel
and FileSystemModel
and Also provide a new Model mechanism that make works with models easier on the QML.
AsemanListModel provides a model component for advanced usage of QML. Below example shows how to use AsemanListModel in your code:
AsemanListModel {
id: model
data: [
{
"name": "bardia",
"age": 30 + 2 // It supports js values too.
},
{
"name": "amir",
"age": 31
}
]
// cachePath store model data to the file and restore it everytime
// Application load again
cachePath: AsemanApp.homePath + "/ages.model"
}
Note: AsemanApp.homePath
returns standard path to store config files.
And You can manage your model using below methods:
var value = model.get(idx, "propertyName");
var allValues = model.get(idx); // allValues.propertyName is equal to value
model.clear();
model.append({"name", "bardia", "age": 30});
var data = model.data; // Get all data of the model as list
var json = Tools.variantToJson(data); // Convert data to json string
You can use AsemanListModelSource
component to pass two or more different sources to the AsemanListModel
:
AsemanListModel {
AsemanListModelSource {
// obj is an object that has a result property, returns variant/array/map
source: obj.result
path: "data->users[2]->childeren"
}
AsemanListModelSource {
source: { title: "test", list: [a, b, c, d] }
path: "list"
}
}
It useful when for example you want to merge two or more requests responses to one model.
There is a mechanism to arrange and change model's data in easier way without even one line JavaScript code using Aseman's Models mechanism. This feature is Hints. You can rename keys (for example change user_name to userName), even change paths of them (for example change results.user.name to userName), change values formats (for example change gregorian date to jalali date), or ... using hints.
AsemanListModel {
...
// Copy "results.user.name" to "userName"
ModelCopyHint {
path: "results->user->name"
targetPath: "userName"
}
// Make all "results.user.nickname" values upperCase
ModelFormatHint {
path: "results->user->nickname"
method: function(arg) { return arg.toUpperCase() }
}
// Convert all keys to camel case.
ModelCamelCaseHint {
}
// Delete "results.images[0].caption"
ModelDeleteHint {
path: "results->images[0]->caption"
}
}
Sql module provides some tools to add SQL features to your applications. It supports SQLite, MySQL, PostgreSQL and also MSSQL. Below example shows how to use it:
import AsemanQml.Sql 2.0
AsemanListModel {
id: model
data: mysql.select("INNER JOIN ...", "title LIKE :title and id > :id", {title: "hi%", id: 10})
// Also you can use it without join and also where arguments.
}
SqlObject {
id: mysql
databaseName: "TestDB"
driver: SqlObject.MySQL
host: "127.0.0.1"; port: 3306
userName: "user"; password: "password"
table: "TestTable"
primaryKeys: ["id"]
property int id: 10
property string title
property date updateTime
Component.onCompleted: {
// It fetchs title and updateTime of id=10 to title and updateTime properties
fetch();
title = "Hi :)"
update(); // Update value,
}
}
SqlObject {
id: sqlite
databaseName: "/Path/to/db"
driver: SqlObject.SQLite
Component.onCompleted: {
var result = query("SOME QUERY");
// You can use queryAsync("SOME QUERY", {...binds...}, function(res){...})
// Method to run queries in async mode
console.debug( Tools.variantToJson(result) );
}
}
These two modules provide access to the MaterialIcons and FontAwesome font icons. The usage is easy:
import AsemanQml.MaterialIcons 2.0
import AsemanQml.Awesome 2.0
Label {
font.family: Awesome.family
text: Awesome.fa_github
}
Label {
font.family: MaterialIcons.family
text: MaterialIcons.mdi_github
}
If you need to access advanced options or create components inherited from QtAseman or even have further use using C++ simply add below line to your .pro
file and use components there:
QT += asemancore asemangui asemanqml asemannetwork asemanwidgets asemangeo
AsemanHttpServer is a qhttp fork, that create routing API for it. So it's async, thread supports and easy to use:
AsemanHttpServer server;
// Sync
server.route("/hello/sync", AsemanHttpServer::HttpMethod::GET, [](const AsemanHttpServer::Request &) {
return QStringLiteral("Hello Sync");
});
// ASync
server.route("/hello/async", AsemanHttpServer::HttpMethod::GET, [](const AsemanHttpServer::Request &, AsemanHttpServer::Responder *responder) {
responder->write(QStringLiteral("Hello ASync"));
});
// ASync Threaded (It will run on another thread automatically)
server.route("/hello/async", AsemanHttpServer::HttpMethod::GET, [](const AsemanHttpServer::Request &, AsemanHttpServer::Responder *responder) {
// Runs on another thread
responder->write(QStringLiteral("Hello ASync"));
}, true);
We have started to document all modules and their essential details using Doxygen standards we will put them in documents folder, but the full documentation process is under developing and not completed yet.