diff --git a/examples/mvvmcore/SampleCore/SampleCore.pro b/examples/mvvmcore/SampleCore/SampleCore.pro index c597dea..2b33227 100644 --- a/examples/mvvmcore/SampleCore/SampleCore.pro +++ b/examples/mvvmcore/SampleCore/SampleCore.pro @@ -10,13 +10,17 @@ HEADERS += \ sampleviewmodel.h \ ieventservice.h \ echoservice.h \ - resultviewmodel.h + resultviewmodel.h \ + drawerviewmodel.h \ + tabviewmodel.h SOURCES += \ samplecoreapp.cpp \ sampleviewmodel.cpp \ echoservice.cpp \ - resultviewmodel.cpp + resultviewmodel.cpp \ + drawerviewmodel.cpp \ + tabviewmodel.cpp target.path = $$[QT_INSTALL_EXAMPLES]/mvvmcore/$$TARGET INSTALLS += target diff --git a/examples/mvvmcore/SampleCore/drawerviewmodel.cpp b/examples/mvvmcore/SampleCore/drawerviewmodel.cpp new file mode 100644 index 0000000..7cb2ba9 --- /dev/null +++ b/examples/mvvmcore/SampleCore/drawerviewmodel.cpp @@ -0,0 +1,31 @@ +#include "drawerviewmodel.h" + +#include "sampleviewmodel.h" + +DrawerViewModel::DrawerViewModel(QObject *parent) : + ViewModel(parent), + _navModel(new QStandardItemModel(0, 1, this)) +{ + _navModel->appendRow(new QStandardItem(tr("Main Sample"))); +} + +DrawerViewModel::~DrawerViewModel() +{ + qInfo(Q_FUNC_INFO); +} + +QStandardItemModel *DrawerViewModel::navModel() const +{ + return _navModel; +} + +void DrawerViewModel::open(int index) +{ + switch (index) { + case 0: + show(); + break; + default: + break; + } +} diff --git a/examples/mvvmcore/SampleCore/drawerviewmodel.h b/examples/mvvmcore/SampleCore/drawerviewmodel.h new file mode 100644 index 0000000..a266155 --- /dev/null +++ b/examples/mvvmcore/SampleCore/drawerviewmodel.h @@ -0,0 +1,26 @@ +#ifndef DRAWERVIEWMODEL_H +#define DRAWERVIEWMODEL_H + +#include +#include + +class DrawerViewModel : public QtMvvm::ViewModel +{ + Q_OBJECT + + Q_PROPERTY(QStandardItemModel* navModel READ navModel CONSTANT) + +public: + Q_INVOKABLE explicit DrawerViewModel(QObject *parent = nullptr); + ~DrawerViewModel(); + + QStandardItemModel* navModel() const; + +public Q_SLOTS: + void open(int index); + +private: + QStandardItemModel* _navModel; +}; + +#endif // DRAWERVIEWMODEL_H diff --git a/examples/mvvmcore/SampleCore/resultviewmodel.cpp b/examples/mvvmcore/SampleCore/resultviewmodel.cpp index a983849..b2014a8 100644 --- a/examples/mvvmcore/SampleCore/resultviewmodel.cpp +++ b/examples/mvvmcore/SampleCore/resultviewmodel.cpp @@ -5,6 +5,11 @@ ResultViewModel::ResultViewModel(QObject *parent) : _result() {} +ResultViewModel::~ResultViewModel() +{ + qInfo(Q_FUNC_INFO); +} + QString ResultViewModel::result() const { return _result; diff --git a/examples/mvvmcore/SampleCore/resultviewmodel.h b/examples/mvvmcore/SampleCore/resultviewmodel.h index 4c8f890..2f8ba2a 100644 --- a/examples/mvvmcore/SampleCore/resultviewmodel.h +++ b/examples/mvvmcore/SampleCore/resultviewmodel.h @@ -11,6 +11,7 @@ class ResultViewModel : public QtMvvm::ViewModel public: Q_INVOKABLE explicit ResultViewModel(QObject *parent = nullptr); + ~ResultViewModel(); QString result() const; diff --git a/examples/mvvmcore/SampleCore/sampleviewmodel.cpp b/examples/mvvmcore/SampleCore/sampleviewmodel.cpp index 735bf07..937bd1b 100644 --- a/examples/mvvmcore/SampleCore/sampleviewmodel.cpp +++ b/examples/mvvmcore/SampleCore/sampleviewmodel.cpp @@ -2,6 +2,7 @@ #include #include #include "resultviewmodel.h" +#include "tabviewmodel.h" const QString SampleViewModel::KeyActive = QStringLiteral("active"); const QString SampleViewModel::KeyNames = QStringLiteral("names"); @@ -64,6 +65,11 @@ void SampleViewModel::setActive(bool active) emit activeChanged(_active); } +void SampleViewModel::showTabs() +{ + show(); +} + void SampleViewModel::getInput() { QtMvvm::getInput(tr("Random input"), diff --git a/examples/mvvmcore/SampleCore/sampleviewmodel.h b/examples/mvvmcore/SampleCore/sampleviewmodel.h index 0452911..d2f6ddc 100644 --- a/examples/mvvmcore/SampleCore/sampleviewmodel.h +++ b/examples/mvvmcore/SampleCore/sampleviewmodel.h @@ -32,6 +32,7 @@ public Q_SLOTS: void setName(QString name); void setActive(bool active); + void showTabs(); void getInput(); void getFiles(); void getResult(); diff --git a/examples/mvvmcore/SampleCore/tabviewmodel.cpp b/examples/mvvmcore/SampleCore/tabviewmodel.cpp new file mode 100644 index 0000000..2381aa5 --- /dev/null +++ b/examples/mvvmcore/SampleCore/tabviewmodel.cpp @@ -0,0 +1,10 @@ +#include "tabviewmodel.h" + +TabViewModel::TabViewModel(QObject *parent) : + ViewModel(parent) +{} + +TabViewModel::~TabViewModel() +{ + qInfo(Q_FUNC_INFO); +} diff --git a/examples/mvvmcore/SampleCore/tabviewmodel.h b/examples/mvvmcore/SampleCore/tabviewmodel.h new file mode 100644 index 0000000..b1c8c46 --- /dev/null +++ b/examples/mvvmcore/SampleCore/tabviewmodel.h @@ -0,0 +1,15 @@ +#ifndef TABVIEWMODEL_H +#define TABVIEWMODEL_H + +#include + +class TabViewModel : public QtMvvm::ViewModel +{ + Q_OBJECT + +public: + Q_INVOKABLE explicit TabViewModel(QObject *parent = nullptr); + ~TabViewModel(); +}; + +#endif // TABVIEWMODEL_H diff --git a/examples/mvvmquick/SampleQuick/DrawerView.qml b/examples/mvvmquick/SampleQuick/DrawerView.qml new file mode 100644 index 0000000..85f5732 --- /dev/null +++ b/examples/mvvmquick/SampleQuick/DrawerView.qml @@ -0,0 +1,26 @@ +import QtQuick 2.10 +import QtQuick.Controls 2.3 +import de.skycoder42.QtMvvm.Sample 1.0 + +ListView { + id: drawerView + + property DrawerViewModel viewModel: null + property Drawer drawer: null + + model: viewModel.navModel + anchors.fill: parent + clip: true + + ScrollBar.vertical: ScrollBar {} + + delegate: ItemDelegate { + width: parent.width + text: viewModel.navModel.data(viewModel.navModel.index(index, 0)) //because "display" is not accessible + + onClicked: { + viewModel.open(index); + drawer.close(); + } + } +} diff --git a/examples/mvvmquick/SampleQuick/SampleView.qml b/examples/mvvmquick/SampleQuick/SampleView.qml index 02adee1..6c7de83 100644 --- a/examples/mvvmquick/SampleQuick/SampleView.qml +++ b/examples/mvvmquick/SampleQuick/SampleView.qml @@ -9,6 +9,7 @@ import de.skycoder42.QtMvvm.Sample 1.0 Page { id: sampleView property SampleViewModel viewModel: null + readonly property bool presentAsRoot: true header: ActionBar { showMenuButton: true @@ -17,6 +18,13 @@ Page { onMenuButtonClicked: QuickPresenter.toggleDrawer() moreMenu: Menu { + MenuItem { + text: qsTr("Show Tabs") + onTriggered: viewModel.showTabs() + } + + MenuSeparator {} + MenuItem { text: qsTr("Another Input") onTriggered: viewModel.getInput() diff --git a/examples/mvvmquick/SampleQuick/TabView.qml b/examples/mvvmquick/SampleQuick/TabView.qml new file mode 100644 index 0000000..8207677 --- /dev/null +++ b/examples/mvvmquick/SampleQuick/TabView.qml @@ -0,0 +1,59 @@ +import QtQuick 2.10 +import QtQuick.Controls 2.3 +import QtQuick.Layouts 1.3 +import de.skycoder42.QtMvvm.Core 1.0 +import de.skycoder42.QtMvvm.Quick 1.0 +import de.skycoder42.quickextras 2.0 +import de.skycoder42.QtMvvm.Sample 1.0 + +Page { + id: tabView + property TabViewModel viewModel: null + + header: ActionBar { + id: bar + showMenuButton: true + //showMenuAsBack: true + title: qsTr("Sample") + + onMenuButtonClicked: QuickPresenter.toggleDrawer() + + tabBar: TabBar { + id: tabBar + currentIndex: swipe.currentIndex + + TabButton { + text: "Test 1" + } + TabButton { + text: "Test 2" + } + } + } + + PresenterProgress {} + + SwipeView { + id: swipe + anchors.fill: parent + currentIndex: bar.tabBarItem.currentIndex + + Pane { + id: firstPage + + Switch { + anchors.centerIn: parent + checked: true + text: qsTr("Click me!") + } + } + Pane { + id: secondPage + + Switch { + anchors.centerIn: parent + text: qsTr("Click me, too!") + } + } + } +} diff --git a/examples/mvvmquick/SampleQuick/main.cpp b/examples/mvvmquick/SampleQuick/main.cpp index efa1b84..e5ff898 100644 --- a/examples/mvvmquick/SampleQuick/main.cpp +++ b/examples/mvvmquick/SampleQuick/main.cpp @@ -12,6 +12,8 @@ #include #include +#include +#include #include "quickeventservice.h" @@ -29,6 +31,8 @@ int main(int argc, char *argv[]) qmlRegisterUncreatableType("de.skycoder42.QtMvvm.Sample", 1, 0, "SampleViewModel", QStringLiteral("ViewModels cannot be created")); qmlRegisterUncreatableType("de.skycoder42.QtMvvm.Sample", 1, 0, "ResultViewModel", QStringLiteral("ViewModels cannot be created")); + qmlRegisterUncreatableType("de.skycoder42.QtMvvm.Sample", 1, 0, "DrawerViewModel", QStringLiteral("ViewModels cannot be created")); + qmlRegisterUncreatableType("de.skycoder42.QtMvvm.Sample", 1, 0, "TabViewModel", QStringLiteral("ViewModels cannot be created")); QtMvvm::QuickPresenter::registerAsPresenter(); @@ -40,5 +44,9 @@ int main(int argc, char *argv[]) if (engine.rootObjects().isEmpty()) return -1; + QObject::connect(coreApp, &QtMvvm::CoreApp::appStarted, coreApp, []() { + coreApp->show(); + }); + return app.exec(); } diff --git a/examples/mvvmquick/SampleQuick/qml.qrc b/examples/mvvmquick/SampleQuick/qml.qrc index 76838f7..67c1e17 100644 --- a/examples/mvvmquick/SampleQuick/qml.qrc +++ b/examples/mvvmquick/SampleQuick/qml.qrc @@ -5,5 +5,7 @@ SampleView.qml ResultView.qml + DrawerView.qml + TabView.qml diff --git a/src/imports/mvvmquick/PresentingDrawer.qml b/src/imports/mvvmquick/PresentingDrawer.qml index 45d1eb3..77e79d5 100644 --- a/src/imports/mvvmquick/PresentingDrawer.qml +++ b/src/imports/mvvmquick/PresentingDrawer.qml @@ -19,7 +19,8 @@ Drawer { function presentDrawerContent(item) { if(_mainChild) _mainChild.destroy(); - item.parent = _presentingDrawer; //TODO test + item.parent = _presentingDrawer.contentItem; //TODO test + item.drawer = _presentingDrawer; _mainChild = item; return true; } diff --git a/src/imports/mvvmquick/PresentingStackView.qml b/src/imports/mvvmquick/PresentingStackView.qml index 1ad443d..5869870 100644 --- a/src/imports/mvvmquick/PresentingStackView.qml +++ b/src/imports/mvvmquick/PresentingStackView.qml @@ -7,26 +7,22 @@ StackView { property int animDuration: 150 property int opDuration: 75 + property var _clearItems: [] + function presentItem(item) { if(item.presentAsRoot) { //TODO document - if(push(item)) + if(safeReplace(null, item)) return true; else return false; } else { - if(replace(null, item)) + if(push(item)) return true; else return false; } } - function safePop(item, operation) { - var resItem = pop(item, operation) - if(resItem) - resItem.destroy(); - } - function closeAction() { if(typeof _presenterStack.currentItem.closeAction == "function") { if(_presenterStack.currentItem.closeAction()) @@ -43,6 +39,37 @@ StackView { } } + function safePop(item, operation) { + var resItem = pop(item, operation) + if(resItem) { + _clearItems.push(resItem); + return true; + } else + return false; + } + + function safeReplace(target, item, properties, operation) { + var items = []; + console.log("current depth: ", depth) + for(var i = depth -1; i >= 0; i--) { + var cItem = get(i, StackView.ForceLoad); + _clearItems.push(cItem); + if(cItem === target) + break; + } + if(replace(target, item, properties, operation)) + return true; + else + return false; + } + + function clearWaitingItems() { + _clearItems.forEach(function(item) { + item.destroy(); + }); + _clearItems = []; + } + //TODO only for android? maybe move to second class? pushEnter: Transition { PropertyAnimation { @@ -63,6 +90,11 @@ StackView { PauseAnimation { duration: _presenterStack.animDuration } + + onRunningChanged: { + if(!running) + Qt.callLater(clearWaitingItems) + } } popEnter: Transition { PauseAnimation { @@ -89,5 +121,12 @@ StackView { duration: _presenterStack.opDuration } } + + onRunningChanged: { + if(!running) + Qt.callLater(clearWaitingItems) + } } + replaceEnter: pushEnter + replaceExit: pushExit } diff --git a/src/imports/mvvmquick/QtMvvmApp.qml b/src/imports/mvvmquick/QtMvvmApp.qml index d84eddb..3401973 100644 --- a/src/imports/mvvmquick/QtMvvmApp.qml +++ b/src/imports/mvvmquick/QtMvvmApp.qml @@ -9,6 +9,7 @@ ApplicationWindow { height: 520 readonly property alias drawer: _drawerLoader.item + property bool rootOnlyDrawer: true PresenterProgress { id: _rootProgress @@ -26,6 +27,8 @@ ApplicationWindow { asynchronous: false sourceComponent: PresentingDrawer { id: _rootDrawer + + interactive: !_root.rootOnlyDrawer || _rootStack.depth == 1 } } @@ -42,8 +45,7 @@ ApplicationWindow { function presentDrawerContent(item) { if(!_drawerLoader.item) _drawerLoader.active = true; - _drawerLoader.item.presentDrawerContent(item); - return false + return _drawerLoader.item.presentDrawerContent(item); } function presentItem(item) { diff --git a/src/mvvmcore/coreapp.cpp b/src/mvvmcore/coreapp.cpp index 4a7d402..5073ef1 100644 --- a/src/mvvmcore/coreapp.cpp +++ b/src/mvvmcore/coreapp.cpp @@ -93,6 +93,7 @@ void CoreApp::bootApp() if(res == EXIT_SUCCESS) { connect(qApp, &QCoreApplication::aboutToQuit, this, &CoreApp::closeApp); + emit appStarted(); } else qApp->exit(res); } diff --git a/src/mvvmcore/coreapp.h b/src/mvvmcore/coreapp.h index e973374..37179d5 100644 --- a/src/mvvmcore/coreapp.h +++ b/src/mvvmcore/coreapp.h @@ -39,6 +39,9 @@ public: public Q_SLOTS: void bootApp(); +Q_SIGNALS: + void appStarted(); + protected: virtual void performRegistrations(); virtual int startApp(const QStringList &arguments) = 0; @@ -69,6 +72,6 @@ inline void CoreApp::show(const QVariantHash ¶ms) } \ Q_COREAPP_STARTUP_FUNCTION(_setup_ ## T ## _hook) -#define coreApp CoreApp::instance() +#define coreApp QtMvvm::CoreApp::instance() #endif // QTMVVM_COREAPP_H