diff --git a/app/inpututils.h b/app/inpututils.h index 122661a0f..e4d9c128f 100644 --- a/app/inpututils.h +++ b/app/inpututils.h @@ -222,7 +222,7 @@ class InputUtils: public QObject /** InputApp platform */ static QString appPlatform(); - static bool isMobilePlatform(); + Q_INVOKABLE static bool isMobilePlatform(); static QString appDataDir(); diff --git a/app/qml/account/MMHowYouFoundUsPage.qml b/app/qml/account/MMHowYouFoundUsPage.qml index d0d231503..96c7e7d1f 100644 --- a/app/qml/account/MMHowYouFoundUsPage.qml +++ b/app/qml/account/MMHowYouFoundUsPage.qml @@ -70,12 +70,13 @@ MMPage { width: parent.width height: parent.height - MMListView { - id: listView - + MMScrollView { width: parent.width height: parent.height + MMListView { + id: listView + spacing: __style.spacing12 topMargin: __style.margin40 @@ -160,6 +161,7 @@ MMPage { } } } + } MMButton { id: footerButton diff --git a/app/qml/components/MMListDrawer.qml b/app/qml/components/MMListDrawer.qml index 4a6a388fd..b22c96a30 100644 --- a/app/qml/components/MMListDrawer.qml +++ b/app/qml/components/MMListDrawer.qml @@ -43,16 +43,18 @@ MMDrawer { } } + MMScrollView { + width: parent.width + height: Math.min( root.drawerContentAvailableHeight, listViewComponent.contentHeight ) + MMListView { id: listViewComponent - width: parent.width - height: Math.min( root.drawerContentAvailableHeight, contentHeight ) - interactive: contentHeight > height clip: true maximumFlickVelocity: __androidUtils.isAndroid ? __style.scrollVelocityAndroid : maximumFlickVelocity } + } } } diff --git a/app/qml/components/MMListMultiselectDrawer.qml b/app/qml/components/MMListMultiselectDrawer.qml index ae9b35e4a..02837cd34 100644 --- a/app/qml/components/MMListMultiselectDrawer.qml +++ b/app/qml/components/MMListMultiselectDrawer.qml @@ -83,13 +83,15 @@ MMDrawer { sourceComponent: defaultEmptyStateComponent } + MMScrollView { + width: parent.width + height: Math.min( listViewComponent.contentHeight, root.drawerContentAvailableHeight - internal.searchBarVerticalSpace ) + + visible: listViewComponent.count > 0 + MMListView { id: listViewComponent - width: parent.width - height: Math.min( contentHeight, root.drawerContentAvailableHeight - internal.searchBarVerticalSpace ) - - visible: count > 0 interactive: contentHeight > height clip: true @@ -122,6 +124,7 @@ MMDrawer { footer: MMListSpacer { height: __style.safeAreaBottom + __style.margin8 + ( root.multiSelect ? confirmButton.height : 0 ) } } + } } } diff --git a/app/qml/components/MMListView.qml b/app/qml/components/MMListView.qml index d1d26e95b..280412870 100644 --- a/app/qml/components/MMListView.qml +++ b/app/qml/components/MMListView.qml @@ -12,6 +12,7 @@ import QtQuick ListView { id: root + // when flicking up really fast, we should go back to the first item onVerticalOvershootChanged: { if (verticalOvershoot < -200) { diff --git a/app/qml/components/MMScrollView.qml b/app/qml/components/MMScrollView.qml index 5ea4c2dea..01b60682e 100644 --- a/app/qml/components/MMScrollView.qml +++ b/app/qml/components/MMScrollView.qml @@ -16,8 +16,10 @@ import QtQuick.Controls ScrollView { id: root + rightPadding: ScrollBar.vertical.visible ? ScrollBar.vertical.width * 2 : 0 + contentWidth: availableWidth // to only scroll vertically - ScrollBar.vertical.policy: ScrollBar.AlwaysOff + ScrollBar.vertical.policy: !__inputUtils.isMobilePlatform() && root.contentHeight > root.height ? ScrollBar.AlwaysOn : ScrollBar.AlwaysOff ScrollBar.horizontal.policy: ScrollBar.AlwaysOff } diff --git a/app/qml/components/MMToolbar.qml b/app/qml/components/MMToolbar.qml index 3e1568fca..41e8c6847 100644 --- a/app/qml/components/MMToolbar.qml +++ b/app/qml/components/MMToolbar.qml @@ -41,17 +41,22 @@ Rectangle { // center the content x: __style.safeAreaLeft + MMScrollView { + anchors.fill: parent + + contentWidth: toolbar.contentWidth + MMListView { id: toolbar onWidthChanged: root.recalculate() model: toolbarModel delegate: ( model.count === 1 ) && ( menuModel.count === 0 ) ? longBtnComp : shortBtnComp - anchors.fill: parent orientation: ListView.Horizontal interactive: false Component.onCompleted: root.initialize() } + } } // buttons shown inside main toolbar diff --git a/app/qml/form/MMFormPage.qml b/app/qml/form/MMFormPage.qml index efb111df5..4cca54500 100644 --- a/app/qml/form/MMFormPage.qml +++ b/app/qml/form/MMFormPage.qml @@ -175,14 +175,15 @@ Page { property int tabIndex: model.TabIndex // from the repeater - MMComponents.MMListView { - + MMComponents.MMScrollView { anchors { fill: parent leftMargin: __style.pageMargins rightMargin: __style.pageMargins } + MMComponents.MMListView { + model: swipeViewRepeater.model.attributeFormProxyModel( pageDelegate.tabIndex ) clip: true @@ -206,6 +207,7 @@ Page { height: 20 * __dp } } + } } } } diff --git a/app/qml/form/MMPreviewDrawer.qml b/app/qml/form/MMPreviewDrawer.qml index 5c0891313..f5b4b6805 100644 --- a/app/qml/form/MMPreviewDrawer.qml +++ b/app/qml/form/MMPreviewDrawer.qml @@ -188,9 +188,12 @@ Item { visible: internal.showFields - MMComponents.MMListView { + MMComponents.MMScrollView { width: parent.width - height: contentHeight + height: listView.contentHeight + + MMComponents.MMListView { + id: listView spacing: __style.margin8 interactive: false @@ -238,6 +241,7 @@ Item { } } } + } } // HTML diff --git a/app/qml/form/components/MMFeaturesListPageDrawer.qml b/app/qml/form/components/MMFeaturesListPageDrawer.qml index b463a687f..7a7c8d3e2 100644 --- a/app/qml/form/components/MMFeaturesListPageDrawer.qml +++ b/app/qml/form/components/MMFeaturesListPageDrawer.qml @@ -96,12 +96,13 @@ Drawer { Layout.preferredHeight: __style.spacing20 } - MMComponents.MMListView { - id: listView - + MMComponents.MMScrollView { Layout.fillWidth: true Layout.fillHeight: true + MMComponents.MMListView { + id: listView + clip: true delegate: MMComponents.MMListDelegate { @@ -114,6 +115,7 @@ Drawer { footer: MMComponents.MMListSpacer { height: __style.safeAreaBottom + __style.margin8 + ( primarybtn.visible ? primarybtn.height : 0 ) } } + } } MMComponents.MMButton { diff --git a/app/qml/form/components/MMFormTabBar.qml b/app/qml/form/components/MMFormTabBar.qml index d7989e412..ac583efea 100644 --- a/app/qml/form/components/MMFormTabBar.qml +++ b/app/qml/form/components/MMFormTabBar.qml @@ -11,49 +11,58 @@ import QtQuick import QtQuick.Controls import "../../components" as MMComponents -MMComponents.MMListView { +MMComponents.MMScrollView { id: root implicitHeight: __style.row45 - spacing: 0 + property alias model: tabList.model + property alias currentIndex: tabList.currentIndex - clip: true - orientation: ListView.Horizontal + contentWidth: tabList.contentWidth - interactive: contentWidth > width + MMComponents.MMListView { + id: tabList - header: MMComponents.MMListSpacer { width: __style.margin20 } - footer: MMComponents.MMListSpacer { width: __style.margin20 } + spacing: 0 - delegate: Control { - id: tabDelegate + clip: true + orientation: ListView.Horizontal - property bool isSelected: ListView.isCurrentItem + interactive: contentWidth > width - height: __style.row45 - width: contentItem.implicitWidth + header: MMComponents.MMListSpacer { width: __style.margin20 } + footer: MMComponents.MMListSpacer { width: __style.margin20 } - focusPolicy: Qt.NoFocus + delegate: Control { + id: tabDelegate - background: Rectangle { - visible: tabDelegate.isSelected - color: __style.grassColor - radius: __style.radius30 - } + property bool isSelected: ListView.isCurrentItem - contentItem: MMComponents.MMText { - text: model.Name + height: __style.row45 + width: contentItem.implicitWidth - font: __style.t4 + focusPolicy: Qt.NoFocus - leftPadding: __style.margin20 - rightPadding: __style.margin20 - } + background: Rectangle { + visible: tabDelegate.isSelected + color: __style.grassColor + radius: __style.radius30 + } + + contentItem: MMComponents.MMText { + text: model.Name + + font: __style.t4 + + leftPadding: __style.margin20 + rightPadding: __style.margin20 + } - MouseArea { - anchors.fill: parent - onClicked: root.currentIndex = index + MouseArea { + anchors.fill: parent + onClicked: root.currentIndex = index + } } } } diff --git a/app/qml/form/editors/MMFormGalleryEditor.qml b/app/qml/form/editors/MMFormGalleryEditor.qml index 37221230b..9812317c6 100644 --- a/app/qml/form/editors/MMFormGalleryEditor.qml +++ b/app/qml/form/editors/MMFormGalleryEditor.qml @@ -35,12 +35,15 @@ MMPrivateComponents.MMBaseInput { ? qsTr( "Some features may be hidden by active filters" ) : "" - inputContent: MMComponents.MMListView { - id: rowView - + inputContent: MMComponents.MMScrollView { width: parent.width height: __style.row120 + contentWidth: rowView.contentWidth + + MMComponents.MMListView { + id: rowView + clip: true spacing: __style.spacing12 orientation: ListView.Horizontal @@ -77,6 +80,7 @@ MMPrivateComponents.MMBaseInput { header: __activeProject.projectRole !== "reader" ? addFeatureComponent : null } + } Component { id: addFeatureComponent diff --git a/app/qml/gps/MMPositionProviderPage.qml b/app/qml/gps/MMPositionProviderPage.qml index 34ceb63ff..d519c2834 100644 --- a/app/qml/gps/MMPositionProviderPage.qml +++ b/app/qml/gps/MMPositionProviderPage.qml @@ -27,12 +27,13 @@ MMComponents.MMPage { width: parent.width height: parent.height - MMComponents.MMListView { - id: listview - + MMComponents.MMScrollView { width: parent.width height: parent.height + MMComponents.MMListView { + id: listview + clip: true model: PositionProvidersModel { @@ -118,6 +119,7 @@ MMComponents.MMPage { height: __style.safeAreaBottom + __style.margin8 + connectNewReceiverButton.height } } + } MMComponents.MMButton { id: connectNewReceiverButton diff --git a/app/qml/layers/MMFeaturesListPage.qml b/app/qml/layers/MMFeaturesListPage.qml index 3d8e03970..4f19f30a7 100644 --- a/app/qml/layers/MMFeaturesListPage.qml +++ b/app/qml/layers/MMFeaturesListPage.qml @@ -65,17 +65,18 @@ MMComponents.MMPage { } } - MMComponents.MMListView { - id: listView - - width: parent.width - + MMComponents.MMScrollView { anchors { top: filterBanner.visible ? filterBanner.bottom : searchBar.bottom bottom: parent.bottom + left: parent.left + right: parent.right topMargin: filterBanner.visible ? __style.spacing10 : __style.spacing20 } + MMComponents.MMListView { + id: listView + model: MM.LayerFeaturesModel { id: featuresModel @@ -97,6 +98,7 @@ MMComponents.MMPage { height: __style.margin20 + ( root.hasToolbar ? 0 : __style.safeAreaBottom ) + ( addButton.visible ? addButton.height : 0 ) } } + } MMComponents.MMBusyIndicator { anchors.centerIn: parent diff --git a/app/qml/layers/MMLayersList.qml b/app/qml/layers/MMLayersList.qml index 0d2fc53e9..d6fddf39f 100644 --- a/app/qml/layers/MMLayersList.qml +++ b/app/qml/layers/MMLayersList.qml @@ -15,7 +15,7 @@ import QtQuick.Layouts import "../components" as MMComponents import "../inputs" -MMComponents.MMListView { +MMComponents.MMScrollView { id: root property var basemodel: null @@ -27,43 +27,49 @@ MMComponents.MMListView { signal nodeClicked( var node, string nodeType, string nodeName ) signal nodeVisibilityClicked( var node ) - model: DelegateModel { - id: delegatemodel + property alias footer: listView.footer - model: root.basemodel + MMComponents.MMListView { + id: listView - delegate: MMComponents.MMListDelegate { + model: DelegateModel { + id: delegatemodel - property bool secondaryTextVisible: root.showNodePath && model.nodePath + model: root.basemodel - text: model.display - secondaryText: secondaryTextVisible ? model.nodePath: "" + delegate: MMComponents.MMListDelegate { - leftContent: Image { - width: __style.icon24 - height: width - sourceSize: Qt.size( width, height) - cache: false // important! Otherwise pixmap providers would not be called for the same id again + property bool secondaryTextVisible: root.showNodePath && model.nodePath - source: root.imageProviderPath + model.serializedNode - } + text: model.display + secondaryText: secondaryTextVisible ? model.nodePath: "" + + leftContent: Image { + width: __style.icon24 + height: width + sourceSize: Qt.size( width, height) + cache: false // important! Otherwise pixmap providers would not be called for the same id again - rightContent: MMComponents.MMSwitch { - visible: model.nodeIsVisible !== "" - checked: model.nodeIsVisible === "yes" - onReleased: { - root.nodeVisibilityClicked( model.node ) + source: root.imageProviderPath + model.serializedNode + } + + rightContent: MMComponents.MMSwitch { + visible: model.nodeIsVisible !== "" + checked: model.nodeIsVisible === "yes" + onReleased: { + root.nodeVisibilityClicked( model.node ) + } } - } - onClicked: root.nodeClicked( model.node, model.nodeType, model.display ) + onClicked: root.nodeClicked( model.node, model.nodeType, model.display ) + } } - } - Component.onCompleted: { - if ( root.parentNodeIndex ) - { - delegatemodel.rootIndex = root.parentNodeIndex + Component.onCompleted: { + if ( root.parentNodeIndex ) + { + delegatemodel.rootIndex = root.parentNodeIndex + } } } } diff --git a/app/qml/project/MMProjectIssuesPage.qml b/app/qml/project/MMProjectIssuesPage.qml index 9812cc085..55546624a 100644 --- a/app/qml/project/MMProjectIssuesPage.qml +++ b/app/qml/project/MMProjectIssuesPage.qml @@ -30,11 +30,12 @@ MMComponents.MMPage { onBackClicked: root.visible = false pageHeader.title: qsTr("Project issues") - pageContent: MMComponents.MMListView { - id: mainList - + pageContent: MMComponents.MMScrollView { anchors.fill: parent + MMComponents.MMListView { + id: mainList + model: root.projectIssuesModel spacing: __style.margin12 @@ -93,4 +94,5 @@ MMComponents.MMPage { } } } + } } diff --git a/app/qml/project/MMProjectList.qml b/app/qml/project/MMProjectList.qml index 7636434b9..1a435c01c 100644 --- a/app/qml/project/MMProjectList.qml +++ b/app/qml/project/MMProjectList.qml @@ -47,55 +47,56 @@ Item { controllerModel.listProjects( searchText ) } - MMComponents.MMListView { - id: listview + MMComponents.MMScrollView { + anchors.fill: parent - Component.onCompleted: { - // set proper footer (add project / fetch more) - if ( root.projectModelType === MM.ProjectsModel.LocalProjectsModel ) { - listview.footer = addProjectComponent - } - else - { - listview.footer = loadingSpinnerComponent + MMComponents.MMListView { + id: listview + + Component.onCompleted: { + // set proper footer (add project / fetch more) + if ( root.projectModelType === MM.ProjectsModel.LocalProjectsModel ) { + listview.footer = addProjectComponent + } + else + { + listview.footer = loadingSpinnerComponent + } } - } - onAtYEndChanged: { - if ( atYEnd ) { // user reached end of the list - if ( controllerModel.hasMoreProjects && !controllerModel.isLoading ) { - controllerModel.fetchAnotherPage( viewModel.searchExpression ) + onAtYEndChanged: { + if ( atYEnd ) { // user reached end of the list + if ( controllerModel.hasMoreProjects && !controllerModel.isLoading ) { + controllerModel.fetchAnotherPage( viewModel.searchExpression ) + } } } - } - anchors.fill: parent - clip: true - spacing: root.spacing + clip: true + spacing: root.spacing - maximumFlickVelocity: __androidUtils.isAndroid ? __style.scrollVelocityAndroid : maximumFlickVelocity + maximumFlickVelocity: __androidUtils.isAndroid ? __style.scrollVelocityAndroid : maximumFlickVelocity - // Proxy model with source projects model - model: MM.ProjectsProxyModel { - id: viewModel + // Proxy model with source projects model + model: MM.ProjectsProxyModel { + id: viewModel - activeProjectAlwaysFirst: root.activeProjectAlwaysFirst - projectSourceModel: MM.ProjectsModel { - id: controllerModel + activeProjectAlwaysFirst: root.activeProjectAlwaysFirst + projectSourceModel: MM.ProjectsModel { + id: controllerModel - merginApi: __merginApi - localProjectsManager: __localProjectsManager - syncManager: __syncManager - modelType: root.projectModelType + merginApi: __merginApi + localProjectsManager: __localProjectsManager + syncManager: __syncManager + modelType: root.projectModelType + } } - } - // Project delegate - delegate: MMProjectComponents.MMProjectDelegate { - id: projectDelegate + // Project delegate + delegate: MMProjectComponents.MMProjectDelegate { + id: projectDelegate - width: ListView.view.width - height: visible ? implicitHeight : 0 + height: visible ? implicitHeight : 0 projectDisplayName: root.projectModelType === MM.ProjectsModel.WorkspaceProjectsModel ? model.ProjectName : model.ProjectFullName projectId: model.ProjectId ? model.ProjectId : "" @@ -178,6 +179,7 @@ Item { onShowChangesRequested: root.showLocalChangesRequested( projectId ) } } + } Component { id: loadingSpinnerComponent diff --git a/app/qml/project/MMProjectStatusPage.qml b/app/qml/project/MMProjectStatusPage.qml index 295d1be3e..702f60bc7 100644 --- a/app/qml/project/MMProjectStatusPage.qml +++ b/app/qml/project/MMProjectStatusPage.qml @@ -47,14 +47,15 @@ MMComponents.MMPage { MMComponents.MMListSpacer { id: spacer; height: __style.spacing40 } // With changes content - MMComponents.MMListView { - id: statusList - + MMComponents.MMScrollView { anchors.top: spacer.bottom anchors.bottom: parent.bottom width: parent.width visible: statusPanel.hasChanges + MMComponents.MMListView { + id: statusList + model: __merginProjectStatusModel spacing: __style.margin8 @@ -144,5 +145,6 @@ MMComponents.MMPage { } } } + } } } diff --git a/app/qml/project/MMProjectWizardPage.qml b/app/qml/project/MMProjectWizardPage.qml index 93a65a10b..f3e40aa1b 100644 --- a/app/qml/project/MMProjectWizardPage.qml +++ b/app/qml/project/MMProjectWizardPage.qml @@ -59,12 +59,14 @@ MMComponents.MMPage { verticalAlignment: Text.AlignVCenter } + MMComponents.MMScrollView { + width: parent.width + height: parent.height - __style.margin20 - projectNameField.height - __style.margin20 - attributesLabel.height + MMComponents.MMListView { id: fieldList model: fieldsModel - width: parent.width - height: parent.height - __style.margin20 - projectNameField.height - __style.margin20 - attributesLabel.height clip: true spacing: __style.margin20 @@ -115,6 +117,7 @@ MMComponents.MMPage { } } } + } } } diff --git a/app/qml/project/components/MMProjectDelegate.qml b/app/qml/project/components/MMProjectDelegate.qml index b858b0666..54d3bcbab 100644 --- a/app/qml/project/components/MMProjectDelegate.qml +++ b/app/qml/project/components/MMProjectDelegate.qml @@ -38,6 +38,9 @@ Control { height: implicitHeight + // shrink to leave room for the list's vertical scrollbar, so content isn't drawn underneath it + implicitWidth: ListView.view.width + topPadding: __style.margin20 rightPadding: __style.margin20 leftPadding: __style.margin20 diff --git a/app/qml/settings/MMChangelogPage.qml b/app/qml/settings/MMChangelogPage.qml index 92b9bf547..a2ffec0a0 100644 --- a/app/qml/settings/MMChangelogPage.qml +++ b/app/qml/settings/MMChangelogPage.qml @@ -21,10 +21,11 @@ MMPage { pageHeader.title: qsTr( "Changelog" ) pageBottomMarginPolicy: MMPage.BottomMarginPolicy.PaintBehindSystemBar - pageContent: MMListView { + pageContent: MMScrollView { width: parent.width height: parent.height + MMListView { spacing: __style.spacing20 model: root.model @@ -49,6 +50,7 @@ MMPage { footer: root.dataNotReady ? noItemDelegate : spacer } + } Component { id: spacer