简短的抒情介绍-在2017年,我碰巧对冥想非常感兴趣。一连串的事件促进了这种情况,这是有利的,但不是很好。多年以来,我一直对清醒梦产生兴趣,但在此之前,我不必专门处理经典的冥想。这些天很多故事从酒吧开始兴趣爱好始于在Google上进行搜索,因此我以这种方式开始了。几乎立即,发现了最流行的冥想应用程序-平静和顶空。
第一个是一个很好的起点(对初学者的出色的教育冥想),第二个我觉得对自己没有用,我不喜欢演示文稿。两者都取消了有偿关税计划(对于俄罗斯联邦,我必须说这是非常昂贵的)。也许我只是不属于需要付费以鼓励自己做某事的人类别:)继续学习Google Play时,我遇到了两个与我精神相近的免费应用程序。第一个是“让我们沉思”-我仍在使用它,第二个将在本文的正文中进行讨论。
应用
因此,经过漫长的搜索,发现了一个完全不起眼的应用程序,然后,如果我没有记错的话,它被称为“冥想。安东诺夫·亚历山大”。事实证明,有可能听到其中四位作者的沉思,实际上是由亚历山大录制和创作的,我们后来与他们见面并结交了朋友。他从字面上用临时工具组装了应用程序,这就像使用WebView的临时SPA,没有任何框架,几乎是裸HTML格式,而Java则最少。它看起来很一般,并且根本没有某些功能(例如,您无法浏览记录,而只能从头开始将其打开)。由于我真的很喜欢内容本身,因此我向亚历山大提供了免费的帮助,帮助他们升级应用程序,因此,可以这么说,“在“他们帮助我的基础上”给我一些东西,我会帮助。“在本文的正文中,我将尝试告诉您我们在开发过程中遇到了哪些问题,做出了哪些决定以及最终发生了什么!我希望本文的各个诀窍能够对任何人都有用,但有趣的是:)
发展的第一阶段
因此,我们为自己设定了目标:
- 保留原始应用程序功能
- 改善UI应用程序和用户UX
- 最小的实现复杂度
t
综上所述,有必要快速创建一个具有相当适度功能的应用程序(目前),对于具有PHP / HTML编程经验的人来说,其代码是可以理解的。坦率地说,我认为选择不赞成Qt是因为:
- 我已经在Qt上有很多开发经验(对于Symbian,MeeGo,Ubuntu Phone以及对Android都有一点经验);
- 在桌面上进行透明开发的可能性,然后在目标设备上进行最终检查;
- 可以使用纯QML创建应用程序,而无需使用C ++。读者当然知道,但是我会澄清-这是一种类似于JavaScript的标记语言,业余爱好者也可以理解。
- 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 .
总的来说,在Qt上进行开发很有趣,免费并且为灵魂做些事情!
PS亲爱的哈布罗夫斯克市民,我希望您不要将其视为广告-该应用程序基本上是免费的并且是非商业性的,我想向有兴趣的人介绍它及其创建历史,就像分享成功找到的开发方法一样。
PSS该应用程序的双胞胎版本为1.1,带有较旧的条目,另外还有5k +下载和100条评论。我们可能会很快将其从商店中取出。