Browse Source

added basic quick presenting flow, with stack

pull/2/head
Skycoder42 7 years ago
parent
commit
a30ec726e2
  1. 6
      .qmake.conf
  2. 6
      examples/mvvmquick/SampleQuick/SampleQuick.pro
  3. 4
      examples/mvvmquick/SampleQuick/main.qml
  4. 10
      src/imports/mvvmcore/mvvmcore.pro
  5. 6
      src/imports/mvvmcore/plugins.qmltypes
  6. 2
      src/imports/mvvmcore/qmldir
  7. 6
      src/imports/mvvmcore/qtmvvmcore_plugin.cpp
  8. 2
      src/imports/mvvmquick/PresenterProgress.qml
  9. 51
      src/imports/mvvmquick/PresentingStackView.qml
  10. 25
      src/imports/mvvmquick/QtMvvmApp.qml
  11. 6
      src/imports/mvvmquick/mvvmquick.pro
  12. 11
      src/imports/mvvmquick/plugins.qmltypes
  13. 2
      src/imports/mvvmquick/qmldir
  14. 30
      src/imports/mvvmquick/qqmlquickpresenter.cpp
  15. 5
      src/imports/mvvmquick/qqmlquickpresenter.h
  16. 6
      src/imports/mvvmquick/qtmvvmquick_plugin.cpp
  17. 44
      src/mvvmquick/quickpresenter.cpp
  18. 6
      src/mvvmquick/quickpresenter.h

6
.qmake.conf

@ -5,4 +5,8 @@ CONFIG += warning_clean exceptions c++14
win32:cross_compile: CONFIG += winrt
DEFINES += QT_DEPRECATED_WARNINGS QT_ASCII_CAST_WARNINGS
MODULE_VERSION = 1.0.0
MODULE_VERSION_MAJOR = 1
MODULE_VERSION_MINOR = 0
MODULE_VERSION_PATCH = 0
MODULE_VERSION_IMPORT = $${MODULE_VERSION_MAJOR}.$${MODULE_VERSION_MINOR}
MODULE_VERSION = $${MODULE_VERSION_MAJOR}.$${MODULE_VERSION_MINOR}.$${MODULE_VERSION_PATCH}

6
examples/mvvmquick/SampleQuick/SampleQuick.pro

@ -40,14 +40,14 @@ else:unix: PRE_TARGETDEPS += $$OUT_PWD/../../mvvmcore/SampleCore/libSampleCore.a
#hacky code to make it possible to use the example from within a shadowed build
samples_in_build {
# first, create a fake qml imports dir
FAKEPATH = qml/de/skycoder42/qtmvvm/quick
ORIGPATH = ../../../../../../../../qml/de/skycoder42/qtmvvm/quick
FAKEPATH = qml/de/skycoder42/QtMvvm/Quick
ORIGPATH = ../../../../../../../../qml/de/skycoder42/QtMvvm/Quick
QMLDEPPATH = $$PWD/../../../src/imports/mvvmquick
system($$QMAKE_MKDIR $$shell_quote($$shell_path($$FAKEPATH)))
# next, symlink all "compiled" files (whole dir for core, as it has no qml files
build_symlink_target.target = create_qml_build_symlinks
build_symlink_target.commands += $$QMAKE_SYMBOLIC_LINK $$shell_path(../../../../../../../qml/de/skycoder42/qtmvvm/core) $$shell_path(qml/de/skycoder42/qtmvvm/core) \
build_symlink_target.commands += $$QMAKE_SYMBOLIC_LINK $$shell_path(../../../../../../../qml/de/skycoder42/QtMvvm/Core) $$shell_path(qml/de/skycoder42/QtMvvm/Core) \
$$escape_expand(\n\t)$$QMAKE_SYMBOLIC_LINK $$shell_path($$ORIGPATH/libdeclarative_mvvmquick.so) $$shell_path($$FAKEPATH/libdeclarative_mvvmquick.so) \
$$escape_expand(\n\t)$$QMAKE_SYMBOLIC_LINK $$shell_path($$ORIGPATH/plugins.qmltypes) $$shell_path($$FAKEPATH/plugins.qmltypes) \
$$escape_expand(\n\t)$$QMAKE_SYMBOLIC_LINK $$shell_path($$ORIGPATH/qmldir) $$shell_path($$FAKEPATH/qmldir)

4
examples/mvvmquick/SampleQuick/main.qml

@ -1,6 +1,6 @@
import QtQuick 2.10
import de.skycoder42.qtmvvm.core 1.0
import de.skycoder42.qtmvvm.quick 1.0
import de.skycoder42.QtMvvm.Core 1.0
import de.skycoder42.QtMvvm.Quick 1.0
QtMvvmApp {
title: qsTr("QtMvvm Quick Sample")

10
src/imports/mvvmcore/mvvmcore.pro

@ -1,18 +1,20 @@
QT += core qml quick mvvmcore
CXX_MODULE = mvvmcore
TARGETPATH = de/skycoder42/qtmvvm/core
TARGETPATH = de/skycoder42/QtMvvm/Core
TARGET = declarative_mvvmcore
IMPORT_VERSION = 1.0
IMPORT_VERSION = $$MODULE_VERSION_IMPORT
DEFINES += "VERSION_MAJOR=$$MODULE_VERSION_MAJOR"
DEFINES += "VERSION_MINOR=$$MODULE_VERSION_MINOR"
HEADERS += \
qtmvvmcore_plugin.h \
qqmlmvvmbinding.h \
qqmlmvvmmessage.h
qqmlmvvmmessage.h
SOURCES += \
qtmvvmcore_plugin.cpp \
qqmlmvvmbinding.cpp \
qqmlmvvmmessage.cpp
qqmlmvvmmessage.cpp
OTHER_FILES += qmldir

6
src/imports/mvvmcore/plugins.qmltypes

@ -4,14 +4,14 @@ import QtQuick.tooling 1.2
// It is used for QML tooling purposes only.
//
// This file was auto-generated by:
// 'qmlplugindump -nonrelocatable de.skycoder42.qtmvvm.core 1.0'
// 'qmlplugindump -nonrelocatable de.skycoder42.QtMvvm.Core 1.0'
Module {
dependencies: ["QtQuick 2.8"]
Component {
name: "QtMvvm::QQmlMvvmBinding"
prototype: "QObject"
exports: ["de.skycoder42.qtmvvm.core/Binding 1.0"]
exports: ["de.skycoder42.QtMvvm.Core/Binding 1.0"]
exportMetaObjectRevisions: [0]
Enum {
name: "BindingDirection"
@ -57,7 +57,7 @@ Module {
Component {
name: "QtMvvm::QQmlMvvmMessage"
prototype: "QObject"
exports: ["de.skycoder42.qtmvvm.core/Message 1.0"]
exports: ["de.skycoder42.QtMvvm.Core/Message 1.0"]
isCreatable: false
isSingleton: true
exportMetaObjectRevisions: [0]

2
src/imports/mvvmcore/qmldir

@ -1,4 +1,4 @@
module de.skycoder42.qtmvvm.core
module de.skycoder42.QtMvvm.Core
plugin declarative_mvvmcore
classname QtMvvmCoreDeclarativeModule
typeinfo plugins.qmltypes

6
src/imports/mvvmcore/qtmvvmcore_plugin.cpp

@ -16,8 +16,12 @@ QtMvvmCoreDeclarativeModule::QtMvvmCoreDeclarativeModule(QObject *parent) :
void QtMvvmCoreDeclarativeModule::registerTypes(const char *uri)
{
Q_ASSERT(qstrcmp(uri, "de.skycoder42.qtmvvm.core") == 0);
Q_ASSERT(qstrcmp(uri, "de.skycoder42.QtMvvm.Core") == 0);
//Version 1.0
qmlRegisterType<QtMvvm::QQmlMvvmBinding>(uri, 1, 0, "Binding");
qmlRegisterSingletonType<QtMvvm::QQmlMvvmMessage>(uri, 1, 0, "Message", createMessageSingleton);
// Check to make shure no module update is forgotten
static_assert(VERSION_MAJOR == 1 && VERSION_MINOR == 0, "QML module version needs to be updated");
}

2
src/imports/mvvmquick/PresenterProgress.qml

@ -1,6 +1,6 @@
import QtQuick 2.10
import QtQuick.Controls 2.3
import de.skycoder42.qtmvvm.quick 1.0
import de.skycoder42.QtMvvm.Quick 1.0
ProgressBar {
visible: QuickPresenter.viewLoading

51
src/imports/mvvmquick/PresentingStackView.qml

@ -1,74 +1,59 @@
import QtQuick 2.10
import QtQuick.Controls 2.3
import de.skycoder42.qtmvvm.quick 1.0
StackView {
id: mainStack
anchors.fill: parent
id: _presenterStack
readonly property int animDuration: 150
readonly property int opDuration: 75
property int animDuration: 150
property int opDuration: 75
function presentItem(item) {
if(push(item)) {
QuickPresenter.qmlPresenter.opened(item);
if(push(item))
return true;
} else
else
return false;
}
function withdrawItem(item) {
if(currentItem === item) {
if(pop()) {
QuickPresenter.qmlPresenter.closed(item);
return true;
}
}
return false;
}
function closeAction() {
if(typeof mainStack.currentItem.closeAction != "undefined") {
if(mainStack.currentItem.closeAction())
if(typeof _presenterStack.currentItem.closeAction == "function") {
if(_presenterStack.currentItem.closeAction())
return true;
}
if(mainStack.depth <= 1)
if(_presenterStack.depth <= 1)
return false;
else {
var item = mainStack.pop();
if(item) {
QuickPresenter.qmlPresenter.closed(item);
if(_presenterStack.pop())
return true;
} else
else
return false;
}
}
//TODO only for android? maybe move to second class?
pushEnter: Transition {
PropertyAnimation {
property: "y"
easing.type: Easing.InOutQuad
from: height * 0.3
to: 0
duration: mainStack.animDuration
duration: _presenterStack.animDuration
}
PropertyAnimation {
property: "opacity"
from: 0.0
to: 1.0
duration: mainStack.opDuration
duration: _presenterStack.opDuration
}
}
pushExit: Transition {
PauseAnimation {
duration: mainStack.animDuration
duration: _presenterStack.animDuration
}
}
popEnter: Transition {
PauseAnimation {
duration: mainStack.animDuration
duration: _presenterStack.animDuration
}
}
popExit: Transition {
@ -77,18 +62,18 @@ StackView {
easing.type: Easing.InOutQuad
from: 0
to: height * 0.3
duration: mainStack.animDuration
duration: _presenterStack.animDuration
}
SequentialAnimation {
PauseAnimation {
duration: mainStack.animDuration - mainStack.opDuration
duration: _presenterStack.animDuration - _presenterStack.opDuration
}
PropertyAnimation {
id: pp1
property: "opacity"
from: 1.0
to: 0.0
duration: mainStack.opDuration
duration: _presenterStack.opDuration
}
}
}

25
src/imports/mvvmquick/QtMvvmApp.qml

@ -1,6 +1,6 @@
import QtQuick 2.10
import QtQuick.Controls 2.3
import de.skycoder42.qtmvvm.quick 1.0
import de.skycoder42.QtMvvm.Quick 1.0
ApplicationWindow {
id: _root
@ -12,8 +12,13 @@ ApplicationWindow {
z: -10 //keep it low so its hidden after the first view was shown
}
PresentingStackView {
id: mainStack
anchors.fill: parent
}
function presentItem(item) {
return true;
return mainStack.presentItem(item);
}
function presentPopup(item) {
@ -21,4 +26,20 @@ ApplicationWindow {
}
Component.onCompleted: QuickPresenter.qmlPresenter = _root
onClosing: {
var closed = false;//messageBox.closeAction();
// if(!closed) {
// if(popups.length > 0) {
// popups[popups.length - 1].close();
// closed = true;
// }
// }
if(!closed)
closed = mainStack.closeAction();
close.accepted = !closed;
}
}

6
src/imports/mvvmquick/mvvmquick.pro

@ -1,8 +1,10 @@
QT += core qml quick mvvmquick mvvmquick-private
CXX_MODULE = mvvmquick
TARGETPATH = de/skycoder42/qtmvvm/quick
TARGETPATH = de/skycoder42/QtMvvm/Quick
TARGET = declarative_mvvmquick
IMPORT_VERSION = 1.0
IMPORT_VERSION = $$MODULE_VERSION_IMPORT
DEFINES += "VERSION_MAJOR=$$MODULE_VERSION_MAJOR"
DEFINES += "VERSION_MINOR=$$MODULE_VERSION_MINOR"
HEADERS += \
qtmvvmquick_plugin.h \

11
src/imports/mvvmquick/plugins.qmltypes

@ -4,14 +4,14 @@ import QtQuick.tooling 1.2
// It is used for QML tooling purposes only.
//
// This file was auto-generated by:
// 'qmlplugindump -nonrelocatable de.skycoder42.qtmvvm.quick 1.0'
// 'qmlplugindump -nonrelocatable de.skycoder42.QtMvvm.Quick 1.0'
Module {
dependencies: ["QtQuick 2.8"]
Component {
name: "QtMvvm::QQmlQuickPresenter"
prototype: "QObject"
exports: ["de.skycoder42.qtmvvm.quick/QuickPresenter 1.0"]
exports: ["de.skycoder42.QtMvvm.Quick/QuickPresenter 1.0"]
isCreatable: false
isSingleton: true
exportMetaObjectRevisions: [0]
@ -30,12 +30,5 @@ Module {
name: "loadingProgressChanged"
Parameter { name: "loadingProgress"; type: "double" }
}
Method {
name: "present"
Parameter { name: "viewModel"; type: "QtMvvm::ViewModel"; isPointer: true }
Parameter { name: "params"; type: "QVariantHash" }
Parameter { name: "viewUrl"; type: "QUrl" }
Parameter { name: "parent"; type: "QPointer<QtMvvm::ViewModel>" }
}
}
}

2
src/imports/mvvmquick/qmldir

@ -1,4 +1,4 @@
module de.skycoder42.qtmvvm.quick
module de.skycoder42.QtMvvm.Quick
plugin declarative_mvvmquick
classname QtMvvmQuickDeclarativeModule
typeinfo plugins.qmltypes

30
src/imports/mvvmquick/qqmlquickpresenter.cpp

@ -105,34 +105,18 @@ void QQmlQuickPresenter::addObject(QQmlComponent *component, ViewModel *viewMode
component->completeCreate();
auto presented = false;
auto cPresenter = QuickPresenterPrivate::currentPresenter();
if(parent && parent->parent())
presented = tryPresent(parent->parent(), item);
presented = cPresenter->presentToQml(parent->parent(), item);
if(!presented)
presented = tryPresent(_qmlPresenter, item);
presented = cPresenter->presentToQml(_qmlPresenter, item);
if(presented)
QQmlEngine::setObjectOwnership(item, QQmlEngine::JavaScriptOwnership);
else {
if(presented) {
if(!item->parent())
QQmlEngine::setObjectOwnership(item, QQmlEngine::JavaScriptOwnership);
} else {
qmlWarning(this) << "Failed to present item for viewModel of type"
<< viewModel->metaObject()->className();
item->deleteLater();
}
}
bool QQmlQuickPresenter::tryPresent(QObject *qmlPresenter, QObject *viewObject)
{
auto meta = qmlPresenter->metaObject();
auto index = -1;
if(viewObject->inherits("QQuickItem"))
index = meta->indexOfMethod("presentItem(QVariant)");
if(viewObject->inherits("QQuickPopup"))
index = meta->indexOfMethod("presentPopup(QVariant)");
QVariant presented = false;
if(index != -1) {
meta->method(index).invoke(qmlPresenter, Qt::DirectConnection,
Q_RETURN_ARG(QVariant, presented),
Q_ARG(QVariant, QVariant::fromValue(viewObject)));
}
return presented.toBool();
}

5
src/imports/mvvmquick/qqmlquickpresenter.h

@ -29,15 +29,13 @@ public:
bool isViewLoading() const;
qreal loadingProgress() const;
public Q_SLOTS:
void present(QtMvvm::ViewModel *viewModel, const QVariantHash &params, const QUrl &viewUrl, QPointer<QtMvvm::ViewModel> parent);
Q_SIGNALS:
void qmlPresenterChanged(QObject* qmlPresenter);
void viewLoadingChanged(bool viewLoading);
void loadingProgressChanged(qreal loadingProgress);
private Q_SLOTS:
void present(QtMvvm::ViewModel *viewModel, const QVariantHash &params, const QUrl &viewUrl, QPointer<QtMvvm::ViewModel> parent);
void statusChanged(QQmlComponent::Status status);
private:
@ -50,7 +48,6 @@ private:
QHash<QQmlComponent*, PresentTuple> _loadCache;
void addObject(QQmlComponent *component, ViewModel *viewModel, const QVariantHash &params, QPointer<ViewModel> parent);
bool tryPresent(QObject *qmlPresenter, QObject *viewObject);
};
}

6
src/imports/mvvmquick/qtmvvmquick_plugin.cpp

@ -16,7 +16,11 @@ QtMvvmQuickDeclarativeModule::QtMvvmQuickDeclarativeModule(QObject *parent) :
void QtMvvmQuickDeclarativeModule::registerTypes(const char *uri)
{
Q_ASSERT(qstrcmp(uri, "de.skycoder42.qtmvvm.quick") == 0);
Q_ASSERT(qstrcmp(uri, "de.skycoder42.QtMvvm.Quick") == 0);
//Version 1.0
qmlRegisterSingletonType<QtMvvm::QQmlQuickPresenter>(uri, 1, 0, "QuickPresenter", createQuickPresenterQmlSingleton);
// Check to make shure no module update is forgotten
static_assert(VERSION_MAJOR == 1 && VERSION_MINOR == 0, "QML module version needs to be updated");
}

44
src/mvvmquick/quickpresenter.cpp

@ -3,6 +3,7 @@
#include <QtCore/QDir>
#include <QtCore/QDirIterator>
#include <QtCore/QMetaMethod>
#include <QtMvvmCore/private/coreapp_p.h>
#include <QtMvvmCore/private/qtmvvm_logging_p.h>
@ -48,6 +49,19 @@ void QuickPresenter::showDialog(const QtMvvm::MessageConfig &config, QtMvvm::Mes
qDebug(Q_FUNC_INFO);
}
bool QuickPresenter::presentToQml(QObject *qmlPresenter, QObject *viewObject)
{
auto meta = qmlPresenter->metaObject();
auto index = presentMethodIndex(meta, viewObject);
QVariant presented = false;
if(index != -1) {
meta->method(index).invoke(qmlPresenter, Qt::DirectConnection,
Q_RETURN_ARG(QVariant, presented),
Q_ARG(QVariant, QVariant::fromValue(viewObject)));
}
return presented.toBool();
}
QUrl QuickPresenter::findViewUrl(const QMetaObject *viewModelType)
{
auto currentMeta = viewModelType;
@ -88,6 +102,36 @@ QUrl QuickPresenter::findViewUrl(const QMetaObject *viewModelType)
return QUrl();
}
int QuickPresenter::presentMethodIndex(const QMetaObject *presenterMetaObject, QObject *viewObject)
{
auto index = -1;
if(viewObject->inherits("QQuickPopup"))
index = presenterMetaObject->indexOfMethod("presentPopup(QVariant)");
if(viewObject->inherits("QQuickItem")) {
if(nameOrClassContains(viewObject, QStringLiteral("Drawer")))
index = presenterMetaObject->indexOfMethod("presentDrawerContent(QVariant)");
if(index == -1 && nameOrClassContains(viewObject, QStringLiteral("Tab")))
index = presenterMetaObject->indexOfMethod("presentTab(QVariant)");
if(index == -1)
index = presenterMetaObject->indexOfMethod("presentItem(QVariant)");
}
return index;
}
bool QuickPresenter::nameOrClassContains(const QObject *obj, const QString &contained, Qt::CaseSensitivity caseSensitive) const
{
if(obj->objectName().contains(contained, caseSensitive))
return true;
auto currentMeta = obj->metaObject();
while(currentMeta) {
if(QString::fromUtf8(currentMeta->className()).contains(contained, caseSensitive))
return true;
currentMeta = currentMeta->superClass();
}
return false;
}
// ------------- Private Implementation -------------
QuickPresenterPrivate::QuickPresenterPrivate() :

6
src/mvvmquick/quickpresenter.h

@ -4,6 +4,7 @@
#include <QtCore/qobject.h>
#include <QtCore/qscopedpointer.h>
#include <QtCore/qurl.h>
#include <QtCore/qmetaobject.h>
#include <QtMvvmCore/ipresenter.h>
#include <QtMvvmCore/coreapp.h>
@ -33,8 +34,13 @@ public:
void present(ViewModel *viewModel, const QVariantHash &params, QPointer<ViewModel> parent) override;
void showDialog(const MessageConfig &config, MessageResult *result) override;
virtual bool presentToQml(QObject *qmlPresenter, QObject *viewObject);
protected:
virtual QUrl findViewUrl(const QMetaObject *viewModelType);
virtual int presentMethodIndex(const QMetaObject *presenterMetaObject, QObject *viewObject);
bool nameOrClassContains(const QObject *obj, const QString &contained, Qt::CaseSensitivity caseSensitive = Qt::CaseInsensitive) const;
private:
friend class QtMvvm::QuickPresenterPrivate;

Loading…
Cancel
Save