From eb2b0f0a3eb9cf84970c9a21dda9553112b99b17 Mon Sep 17 00:00:00 2001 From: Dirk Hohndel Date: Mon, 4 Jan 2021 15:47:33 +0100 Subject: [PATCH] mobile/statistics: add a statistics page on mobile This adds a reasonably flexibile mobile page that tries to do the right thing for both portrait and landscape mode. In order to get the most out of a mobile screen, it's implemented in a way that always gives it the full screen (it does so by emptying out the page stack and being the only page shown - brutal, but effective). This commit also contains a bunch of other random cleanups that didn't really justify being in separate commits. Parts of this was written by Berthold, hence the double SOB. Signed-off-by: Dirk Hohndel Signed-off-by: Berthold Stoeger --- mobile-widgets/qml/StatisticsPage.qml | 119 ++++++++++++++++++++++++ mobile-widgets/qml/main.qml | 24 ++++- mobile-widgets/qml/mobile-resources.qrc | 1 + mobile-widgets/statsmanager.cpp | 63 ++++++++++++- mobile-widgets/statsmanager.h | 25 ++++- 5 files changed, 229 insertions(+), 3 deletions(-) create mode 100644 mobile-widgets/qml/StatisticsPage.qml diff --git a/mobile-widgets/qml/StatisticsPage.qml b/mobile-widgets/qml/StatisticsPage.qml new file mode 100644 index 000000000..4119c653a --- /dev/null +++ b/mobile-widgets/qml/StatisticsPage.qml @@ -0,0 +1,119 @@ +// SPDX-License-Identifier: GPL-2.0 +import QtQuick 2.6 +import QtQuick.Controls 2.4 +import QtQuick.Layouts 1.2 +import org.subsurfacedivelog.mobile 1.0 +import org.kde.kirigami 2.4 as Kirigami + +Kirigami.Page { + id: statisticsPage + objectName: "StatisticsPage" + title: qsTr("Statistics") + leftPadding: 0 + topPadding: 0 + rightPadding: 0 + bottomPadding: 0 + width: rootItem.width + implicitWidth: rootItem.width + property bool wide: width > height + StatsManager { + id: statsManager + } + onVisibleChanged: { + if (visible) + statsManager.doit() + } + + GridLayout { + anchors.fill: parent + ColumnLayout { + id: i1 + Layout.column: 0 + Layout.row: 0 + Layout.margins: Kirigami.Units.smallSpacing + TemplateLabelSmall { + text: qsTr("Base variable") + } + TemplateComboBox { + id: var1 + model: statsManager.var1List + Layout.fillWidth: false + onCurrentIndexChanged: { + statsManager.var1Changed(currentIndex) + } + } + } + ColumnLayout { + id: i2 + Layout.column: wide ? 0 : 1 + Layout.row: wide ? 1 : 0 + Layout.margins: Kirigami.Units.smallSpacing + TemplateLabelSmall { + text: qsTr("Binning") + } + TemplateComboBox { + id: var1Binner + model: statsManager.binner1List + Layout.fillWidth: false + onCurrentIndexChanged: { + statsManager.var1BinnerChanged(currentIndex) + } + } + } + ColumnLayout { + id: i3 + Layout.column: wide ? 0 : 2 + Layout.row: wide ? 2 : 0 + Layout.margins: Kirigami.Units.smallSpacing + TemplateLabelSmall { + text: qsTr("Data") + } + TemplateComboBox { + id: var2 + model: statsManager.var2List + Layout.fillWidth: false + onCurrentIndexChanged: { + statsManager.var2Changed(currentIndex) + } + } + } + ColumnLayout { + id: i4 + Layout.column: wide ? 0 : 3 + Layout.row: wide ? 3 : 0 + Layout.margins: Kirigami.Units.smallSpacing + TemplateLabelSmall { + text: qsTr("Binning") + } + TemplateComboBox { + id: var2Binner + model: statsManager.binner2List + Layout.fillWidth: false + onCurrentIndexChanged: { + statsManager.var2BinnerChanged(currentIndex) + } + } + } + Item { + Layout.column: wide ? 0 : 4 + Layout.row: wide ? 4 : 0 + Layout.preferredHeight: wide ? parent.height - Kirigami.Units.gridUnit * 16 : Kirigami.Units.gridUnit + Layout.preferredWidth: wide ? parent.width - i1.implicitWidt - i2.implicitWidt - i3.implicitWidt - i4.implicitWidth : Kirigami.Units.gridUnit + // just used for spacing + } + + StatsView { + Layout.row: wide ? 0 : 1 + Layout.column: wide ? 1 : 0 + Layout.rowSpan: wide ? 5 : 1 + Layout.columnSpan: wide ? 1 : 5 + id: statsView + Layout.fillWidth: true + Layout.fillHeight: true + } + } + Component.onCompleted: { + statsManager.init(statsView, var1) + console.log("Statistics widget loaded") + } +} diff --git a/mobile-widgets/qml/main.qml b/mobile-widgets/qml/main.qml index 4f5344275..837b29b59 100644 --- a/mobile-widgets/qml/main.qml +++ b/mobile-widgets/qml/main.qml @@ -88,6 +88,9 @@ Kirigami.ApplicationWindow { for (var i=pageStack.depth; i>1; i--) { pageStack.pop() } + if (pageStack.currentItem !== diveList) { + showDiveList() + } detailsWindow.endEditMode() } @@ -96,6 +99,15 @@ Kirigami.ApplicationWindow { } function showPage(page) { + if (page === statistics) { + manager.appendTextToLog("switching to statistics page, clearing out stack") + pageStack.clear() + } + if (pageStack.currentItem === statistics) { + manager.appendTextToLog("switching away from statistics page, clearing out stack") + pageStack.clear() + } + if (page !== mapPage) hackToOpenMap = 0 // we really want a different page if (globalDrawer.drawerOpen) @@ -440,6 +452,12 @@ if you have network connectivity and want to sync your data to cloud storage."), } } }, + Kirigami.Action { + text: qsTr("Statistics") + onTriggered: { + showPage(statistics) + } + }, Kirigami.Action { icon { name: ":/icons/ic_settings.svg" @@ -859,9 +877,13 @@ if you have network connectivity and want to sync your data to cloud storage."), visible: false } + StatisticsPage { + id: statistics + visible: false + } + Settings { id: settingsWindow - visible: false } CopySettings { diff --git a/mobile-widgets/qml/mobile-resources.qrc b/mobile-widgets/qml/mobile-resources.qrc index 00ef4f868..d0b285ab6 100644 --- a/mobile-widgets/qml/mobile-resources.qrc +++ b/mobile-widgets/qml/mobile-resources.qrc @@ -37,6 +37,7 @@ Log.qml main.qml MapPage.qml + StatisticsPage.qml Settings.qml CopySettings.qml ThemeTest.qml diff --git a/mobile-widgets/statsmanager.cpp b/mobile-widgets/statsmanager.cpp index 2864a5f16..d149c9978 100644 --- a/mobile-widgets/statsmanager.cpp +++ b/mobile-widgets/statsmanager.cpp @@ -7,13 +7,14 @@ StatsManager::StatsManager() : view(nullptr) state.var1Changed(2); state.var2Changed(3); state.binner2Changed(2); + updateUi(); } StatsManager::~StatsManager() { } -void StatsManager::init(StatsView *v) +void StatsManager::init(StatsView *v, QObject *o) { if (!v) fprintf(stderr, "StatsManager::init(): no StatsView - statistics will not work.\n"); @@ -26,3 +27,63 @@ void StatsManager::doit() return; view->plot(state); } + +static void setVariableList(const StatsState::VariableList &list, QStringList &stringList) +{ + stringList.clear(); + for (const StatsState::Variable &v: list.variables) + stringList.push_back(v.name); +} + +static void setBinnerList(const StatsState::BinnerList &list, QStringList &stringList) +{ + stringList.clear(); + for (const QString &v: list.binners) + stringList.push_back(v); +} + +void StatsManager::updateUi() +{ + uiState = state.getUIState(); + setVariableList(uiState.var1, var1List); + setBinnerList(uiState.binners1, binner1List); + setVariableList(uiState.var2, var2List); + setBinnerList(uiState.binners2, binner2List); + var1ListChanged(); + binner1ListChanged(); + var2ListChanged(); + binner2ListChanged(); + + if (view) + view->plot(state); +} + +void StatsManager::var1Changed(int idx) +{ + if (uiState.var1.variables.empty()) + return; + idx = std::clamp(idx, 0, (int)uiState.var1.variables.size()); + state.var1Changed(uiState.var1.variables[idx].id); + updateUi(); +} + +void StatsManager::var1BinnerChanged(int idx) +{ + state.binner1Changed(idx); + updateUi(); +} + +void StatsManager::var2Changed(int idx) +{ + if (uiState.var2.variables.empty()) + return; + idx = std::clamp(idx, 0, (int)uiState.var2.variables.size()); + state.var2Changed(uiState.var2.variables[idx].id); + updateUi(); +} + +void StatsManager::var2BinnerChanged(int idx) +{ + state.binner2Changed(idx); + updateUi(); +} diff --git a/mobile-widgets/statsmanager.h b/mobile-widgets/statsmanager.h index 3cae244c0..bfdf6724b 100644 --- a/mobile-widgets/statsmanager.h +++ b/mobile-widgets/statsmanager.h @@ -5,16 +5,39 @@ #include "stats/statsview.h" #include "stats/statsstate.h" +#include + class StatsManager : public QObject { Q_OBJECT public: + Q_PROPERTY(QStringList var1List MEMBER var1List NOTIFY var1ListChanged) + Q_PROPERTY(QStringList binner1List MEMBER binner1List NOTIFY binner1ListChanged) + Q_PROPERTY(QStringList var2List MEMBER var2List NOTIFY var2ListChanged) + Q_PROPERTY(QStringList binner2List MEMBER binner2List NOTIFY binner2ListChanged) + StatsManager(); ~StatsManager(); - Q_INVOKABLE void init(StatsView *v); + Q_INVOKABLE void init(StatsView *v, QObject *o); Q_INVOKABLE void doit(); + Q_INVOKABLE void var1Changed(int idx); + Q_INVOKABLE void var1BinnerChanged(int idx); + Q_INVOKABLE void var2Changed(int idx); + Q_INVOKABLE void var2BinnerChanged(int idx); +signals: + void var1ListChanged(); + void binner1ListChanged(); + void var2ListChanged(); + void binner2ListChanged(); private: StatsView *view; StatsState state; + QStringList var1List; + QStringList binner1List; + QStringList var2List; + QStringList binner2List; + StatsState::UIState uiState; // Remember UI state so that we can interpret indexes + void updateUi(); + }; #endif