Pengantar liris singkat - pada 2017, saya sangat tertarik pada meditasi. Ini difasilitasi oleh seluruh rangkaian acara, menguntungkan dan tidak terlalu. Selama bertahun-tahun saya telah tertarik dan mempraktikkan mimpi jernih, tetapi sebelum itu saya tidak harus berurusan secara khusus dengan meditasi dalam bentuk kanonik mereka. Saat ini, banyakcerita dimulai di barHobi dimulai dengan pencarian di Google, jadi saya memulainya dengan cara itu. Hampir segera, aplikasi meditasi paling populer ditemukan - Tenang dan Headspace.
Yang pertama berfungsi sebagai titik awal yang baik (meditasi pendidikan yang sangat baik untuk pemula), yang kedua saya merasa tidak berguna untuk diri saya sendiri, saya tidak suka presentasi. Keduanya terdorong pergi dengan rencana tarif berbayar mereka (dan saya harus mengatakan sangat mahal untuk Federasi Rusia). Mungkin saya hanya tidak termasuk dalam kategori orang yang perlu membayar untuk mendorong diri mereka untuk melakukan sesuatu :) Terus belajar Google play, saya menemukan dua aplikasi gratis yang dekat dengan saya dalam semangat. Yang pertama adalah "Ayo Bermeditasi" - Saya masih menggunakannya, yang kedua akan dibahas dalam tubuh artikel.
aplikasi
Jadi, setelah pencarian yang cukup lama, aplikasi yang sama sekali tidak mencolok ditemukan, kemudian dipanggil, jika saya tidak salah, "Meditasi. Antonov Alexander." Ternyata, adalah mungkin untuk mendengarkan meditasi empat penulis di dalamnya, direkam dan disusun, pada kenyataannya, oleh Alexander, yang kemudian kita temui dan berteman. Dia merakit aplikasi secara harfiah dari alat improvisasi sendiri, itu seperti SPA buatan sendiri menggunakan WebView tanpa kerangka kerja, praktis dalam HTML telanjang dan minimal di Jawa. Itu terlihat begitu-begitu, dan beberapa fungsi tidak ada (misalnya, Anda tidak dapat menavigasi melalui rekaman, tetapi hanya menyalakannya dari awal). Karena saya sangat menyukai kontennya, saya menawarkan Alexander bantuan gratis saya untuk meningkatkan aplikasi, jadi, untuk berbicara, "untuk memberikan sesuatu kembali "atas dasar" mereka membantu saya, saya akan membantu. "Dalam tubuh artikel saya akan mencoba untuk memberi tahu Anda apa masalah yang kami temui selama pengembangan, keputusan apa yang dibuat, dan apa yang terjadi pada akhirnya! Saya berharap bahwa masing-masing resep artikel akan menjadi berguna untuk siapa saja, tetapi menarik :)
, :
Qt
β (), PHP/HTML. , , , Qt, :
- Qt ( Symbian, MeeGo, Ubuntu Phone Android);
- , ;
- QML, C++. , β JavaScript-like , ;
- iOS ( ).
UI
, , . , , . , . ( ):

"" anchors, Row, Column Repeater. , UI. , ( ):
Button {
id: mainButton
anchors {
left: parent.left
right: parent.right
}
height: btnLayout.height + 30
Material.background: "white"
onClicked: stackView.push(Qt.resolvedUrl("qrc:/qml/MeditationListPage.qml"))
Column {
id: btnLayout
spacing: 10
anchors {
top: parent.top
topMargin: 15
left: parent.left
right: parent.right
margins: 10
}
Row {
anchors.horizontalCenter: parent.horizontalCenter
spacing: (mainButton.width - 4 * 50) / 6
Repeater {
model: meditationModel
RoundedIcon {
source: Qt.resolvedUrl("qrc:/img/my%1.png".arg(model.index))
color: model.color
width: 50
height: 50
}
}
}
Label {
text: qsTr("")
font.pointSize: 14
color: "dimgrey"
anchors.horizontalCenter: parent.horizontalCenter
}
Label {
text: " , "
anchors {
left: parent.left
right: parent.right
}
horizontalAlignment: Text.AlignHCenter
Material.foreground: Material.Grey
font.pixelSize: 12
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
}
}
}
UI , HDPI Qt . , Qt: QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
. " ".
Material design, Android Qt Quick Controls 2 . https://doc.qt.io/qt-5/qtquickcontrols2-material.html. , Material design. UI , attached property Material.accent
.

mp3- , QRC. 10-15 . β , 15 . , , pro-:
CONFIG += resources_big
, , , .
, " ". Shorts, , . DarkModeShader.qml
:
ShaderEffect {
fragmentShader: "
uniform lowp sampler2D source;
uniform lowp float qt_Opacity;
varying highp vec2 qt_TexCoord0;
void main() {
lowp vec4 p = texture2D(source, qt_TexCoord0);
p.r = min(0.8, (1.0 - p.r) * 0.8 + 0.1);
p.g = min(0.8, (1.0 - p.g) * 0.8 + 0.1);
p.b = min(0.8, (1.0 - p.b) * 0.8 + 0.1);
gl_FragColor = vec4(vec3(dot(p.rgb, vec3(0.299, 0.587, 0.114))), p.a) * qt_Opacity;
}
"
}
:
StackView {
// ...
layer.effect: DarkModeShader { }
layer.enabled: optionsKeeper.isNightMode
}
.. , isNightMode
. Qt / ( , ).
, β . - , β !
Qt Multimedia, Audio
. mp3, , β , :
Audio {
id: audioPlayback
source: meditAudioSource
}
// ...
Slider {
anchors {
left: parent.left
right: playBtn.left
verticalCenter: parent.verticalCenter
}
from: 0
to: audioPlayback.duration
value: audioPlayback.position
onMoved: audioPlayback.seek(value)
Material.accent: meditColor
}
Settings
Qt.labs.settings
(, , labs):
import Qt.labs.settings 1.0
// ... boilerplate- , .
property Settings settings: Settings {
property bool isNightMode: false
}
2018 , .
, , 2020, , - , β ( ). , β β :)
, JSON- . . HTTP- QML- XMLHttpRequest
( JSON QML). .
. QML LocalStorage, SQLite. JS-, QML, :
// databasemodule.js
.pragma library // I hope this will prevent the waste of memory.
.import QtQuick.LocalStorage 2.0 as SQL
function getMeditations() {
...
}
// TransferManager.qml
import "databasemodule.js" as DB
...
var syncedItems = DB.getMeditations()
:
var db = SQL.LocalStorage.openDatabaseSync("AMeditation", "", "Main DB", 100000)
...
db.transaction(function(tx) {
dbResult = tx.executeSql("SELECT * FROM meditations")
console.log("meditations SELECTED: ", dbResult.rows.length)
})
.. , transaction
callback. ( , Qt ).
. openDatabaseSync
. , ( , ). . , , , . [" ", " ", " "]:
var migrations = [
{'from': "", 'to': "1.0", 'ops': function(transaction) {
transaction.executeSql("CREATE TABLE meditations ( \
id INTEGER PRIMARY KEY
...
status TEXT);")
}}
,{'from': "1.0", 'to': "1.1", 'ops': function(transaction) {
transaction.executeSql("ALTER TABLE meditations ADD quality TEXT;")
}}
]
, ( β , - ).
C++
QML, C++. . Ubuntu Phone. . QML β . C++- QML :
engine.rootContext()->setContextProperty("networkManager", new NetworkManager());
QML - :
// .
var isSucces = networkManager.download(downloadUrl, currentDownload.localUrl)
...
// .
Connections {
target: networkManager
onDownloadOperationProgress: {
d.currentDownload.current = current
d.currentDownload.total = total
}
...
}
C++-, QML- singletone :
class CppUtils : public QObject
{
Q_OBJECT
public:
explicit CppUtils(QObject *parent = nullptr);
~CppUtils();
Q_INVOKABLE bool removeFile(const QString& fileName) const;
static QObject *cppUtilsSingletoneProvider(QQmlEngine *engine, QJSEngine *scriptEngine);
};
qmlRegisterSingletonType<CppUtils>("AMeditation.CppUtils", 1, 0, "CppUtils", CppUtils::cppUtilsSingletoneProvider);
.. , cppUtilsSingletoneProvider
, Q_INVOKABLE β "" QML. QML :
import AMeditation.CppUtils 1.0
// ...
CppUtils.removeFile(cd.localUrl)
, - . β . , - , . , . QML (QNetworkAccessManager). . :
class CachingNetworkAccessManager : public QNetworkAccessManager
{
public:
CachingNetworkAccessManager(QObject *parent = 0);
protected:
QNetworkReply* createRequest(Operation op, const QNetworkRequest &req, QIODevice *outgoingData = 0);
};
class CachingNetworkManagerFactory : public QQmlNetworkAccessManagerFactory
{
public:
CachingNetworkManagerFactory();
QNetworkAccessManager *create(QObject *parent);
};
QNetworkReply* CachingNetworkAccessManager::createRequest(Operation op, const QNetworkRequest &request, QIODevice *outgoingData)
{
QNetworkRequest req(request);
req.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferNetwork);
return QNetworkAccessManager::createRequest(op, req, outgoingData);
}
QNetworkAccessManager *CachingNetworkManagerFactory::create(QObject *parent) {
QNetworkAccessManager* manager = new CachingNetworkAccessManager(parent);
QNetworkDiskCache* cache = new QNetworkDiskCache(manager);
cache->setCacheDirectory(QString("%1/network").arg(QStandardPaths::writableLocation(QStandardPaths::CacheLocation)));
manager->setCache(cache);
return manager;
}
.. setCache
, createRequest
. β , .
Android
SDK NDK. Linux- , Windows - (, , QtCreator 4.12 NDK, ). NDK Clang. arm_v7 (32 ), arm_v8a (64 ; Google play 2019 ). Google play.
, , .
- Qt pet-, Android. ;
- AMeditation ( UI " 2.1. ") 10+ 250 , ( , , ).
- , , !
- iOS .
Secara umum, mengembangkan Qt itu menyenangkan, melakukan sesuatu secara gratis dan untuk jiwa juga!
PS Warga Khabrovsk yang terhormat, saya harap Anda tidak menganggapnya sebagai iklan - aplikasi ini pada dasarnya gratis dan non-komersial, saya ingin menceritakan tentang hal itu dan sejarah pembuatannya kepada mereka yang tertarik, hanya ingin berbagi pendekatan pembangunan yang berhasil ditemukan.
PSS Aplikasi ini memiliki versi kembarannya 1.1 dengan entri yang lebih lama, yang memiliki unduhan 5k + lainnya dan 100 ulasan. Kami mungkin akan segera mengeluarkannya dari toko.