diff --git a/app/icons/ProjectButtonMore.svg b/app/icons/ProjectButtonMore.svg new file mode 100644 index 000000000..d8773b76f --- /dev/null +++ b/app/icons/ProjectButtonMore.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/app/icons/Stop.svg b/app/icons/Stop.svg new file mode 100644 index 000000000..d022fd4ae --- /dev/null +++ b/app/icons/Stop.svg @@ -0,0 +1,4 @@ + + + + diff --git a/app/icons/icons.qrc b/app/icons/icons.qrc index 832b11c2e..ec511e779 100644 --- a/app/icons/icons.qrc +++ b/app/icons/icons.qrc @@ -20,5 +20,7 @@ Done.svg Edit.svg More.svg + ProjectButtonMore.svg + Stop.svg diff --git a/app/mmstyle.h b/app/mmstyle.h index 781dfd00d..ca43e1e81 100644 --- a/app/mmstyle.h +++ b/app/mmstyle.h @@ -93,6 +93,8 @@ class MMStyle: public QObject Q_PROPERTY( QUrl doneIcon READ doneIcon CONSTANT ) Q_PROPERTY( QUrl editIcon READ editIcon CONSTANT ) Q_PROPERTY( QUrl moreIcon READ moreIcon CONSTANT ) + Q_PROPERTY( QUrl projectButtonMoreIcon READ projectButtonMoreIcon CONSTANT ) + Q_PROPERTY( QUrl stopIcon READ stopIcon CONSTANT ) // Images Q_PROPERTY( QUrl uploadImage READ uploadImage CONSTANT ) @@ -173,6 +175,8 @@ class MMStyle: public QObject QUrl doneIcon() {return QUrl( "qrc:/Done.svg" );} QUrl editIcon() {return QUrl( "qrc:/Edit.svg" );} QUrl moreIcon() {return QUrl( "qrc:/More.svg" );} + QUrl projectButtonMoreIcon() {return QUrl( "qrc:/ProjectButtonMore.svg" );} + QUrl stopIcon() {return QUrl( "qrc:/Stop.svg" );} QUrl uploadImage() {return QUrl( "qrc:/UploadImage.svg" );} QUrl reachedDataLimitImage() {return QUrl( "qrc:/ReachedDataLimitImage.svg" );} diff --git a/app/qml/components/MMProjectItem.qml b/app/qml/components/MMProjectItem.qml new file mode 100644 index 000000000..98571c3f0 --- /dev/null +++ b/app/qml/components/MMProjectItem.qml @@ -0,0 +1,446 @@ +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Qt5Compat.GraphicalEffects +import QtQml.Models + +import ".." + +Rectangle { + id: root + + // Required properties + property string projectDisplayName: "TITLE" + property string projectId: "ID" + property string projectDescription: "DESC" + property int projectStatus: 0 + property bool projectIsValid: true + property bool projectIsPending: false + property real projectSyncProgress: 10 + property bool projectIsLocal: true + property bool projectIsMergin: true + property string projectRemoteError: "ERROR" + + property color primaryColor: "red" //InputStyle.clrPanelMain + property color secondaryColor: "green"// InputStyle.fontColor + property real itemMargin: 20 //InputStyle.panelMargin + + property color iconColor: "yellow" // root.highlight ? root.primaryColor : InputStyle.actionColor + property real iconSize: height * 0.3 + property real borderWidth: 1 * __dp + property real menuItemHeight: height * 0.8 + + property real viewContentY: 0 + property real viewHeight: 0 + property bool highlight: false + + signal openRequested() + signal syncRequested() + signal migrateRequested() + signal removeRequested() + signal stopSyncRequested() + signal showChangesRequested() + + + color: root.highlight ? __style.forestColor : __style.whiteColor + radius: 12 * __dp + height: mainColumn.height + + Column { + id: mainColumn + + width: parent.width + padding: 20 * __dp + spacing: 12 * __dp + + Row { + id: row + spacing: 6 * __dp + + Column { + id: column + spacing: 6 * __dp + + Text { + text: root.projectDisplayName + font: __style.t3 + color: root.highlight ? __style.whiteColor : __style.nightColor + elide: Text.ElideRight + width: mainColumn.width - 2 * mainColumn.padding - icon.width - row.spacing + } + + Text { + text: root.projectDescription + font: __style.p6 + color: root.highlight ? __style.whiteColor : __style.nightColor + elide: Text.ElideRight + width: mainColumn.width - 2 * mainColumn.padding - icon.width - row.spacing + } + } + + Image { + id: icon + + source: __style.projectButtonMoreIcon + height: column.height + fillMode: Image.PreserveAspectFit + } + } + + MMProgressBar { + position: 0.5 + width: mainColumn.width - 2 * mainColumn.padding + } + + Row { + id: syncRow + spacing: 6 * __dp + + Text { + text: qsTr("Synchronising...") + font: __style.p6 + color: root.highlight ? __style.whiteColor : __style.nightColor + elide: Text.ElideRight + width: mainColumn.width - 2 * mainColumn.padding - stopIcon.width - syncRow.spacing * 2 - stopText.width + verticalAlignment: Text.AlignVCenter + anchors.verticalCenter: parent.verticalCenter + } + MMIcon { + id: stopIcon + + source: __style.stopIcon + anchors.verticalCenter: parent.verticalCenter + color: root.highlight ? __style.whiteColor : __style.forestColor + + MouseArea { + anchors.fill: parent + onClicked: root.stopSyncRequested() + } + } + Text { + id: stopText + + text: qsTr("Stop") + font: __style.t4 + color: root.highlight ? __style.whiteColor : __style.nightColor + verticalAlignment: Text.AlignVCenter + anchors.verticalCenter: parent.verticalCenter + + MouseArea { + anchors.fill: parent + onClicked: root.stopSyncRequested() + } + } + } + } + + ///* + // function getStatusIcon() { + // if ( projectIsPending ) + // return InputStyle.stopIcon + + // if ( projectIsLocal && projectIsMergin ) { + // // downloaded mergin projects + // if ( projectStatus === ProjectStatus.NeedsSync ) { + // return InputStyle.syncIcon + // } + // return "" // no icon if this project does not have changes + // } + + // if ( projectIsMergin && projectStatus === ProjectStatus.NoVersion ) + // return InputStyle.downloadIcon + + // if ( projectIsLocal && projectStatus === ProjectStatus.NoVersion ) + // return InputStyle.uploadIcon + + // return "" + // } + + // function getMoreMenuItems() { + // if ( projectIsMergin && projectIsLocal ) + // { + // if ( ( projectStatus === ProjectStatus.NeedsSync ) ) + // return "sync,changes,remove" + + // return "changes,remove" + // } + // else if ( !projectIsMergin && projectIsLocal ) + // return "upload,remove" + // else + // return "download" + // } + + // function fillMoreMenu() { + // // fill more menu with corresponding items + // let itemsMap = { + // "sync": { + // "name": qsTr("Synchronize project"), + // "iconSource": InputStyle.syncIcon, + // "callback": function() { root.syncRequested() } + // }, + // "changes": { + // "name": qsTr("Local changes"), + // "iconSource": InputStyle.infoIcon, + // "callback": function() { root.showChangesRequested() } + // }, + // "remove": { + // "name": qsTr("Remove from device"), + // "iconSource": InputStyle.removeIcon, + // "callback": function() { root.removeRequested() } + // }, + // "upload": { + // "name": qsTr("Upload to Mergin"), + // "iconSource": InputStyle.uploadIcon, + // "callback": function() { root.migrateRequested() } + // }, + // "download": { + // "name": qsTr("Download from Mergin"), + // "iconSource": InputStyle.downloadIcon, + // "callback": function() { root.syncRequested() } + // } + // } + + // let items = getMoreMenuItems() + // items = items.split(',') + + // // clear previous items + // while( contextMenu.count > 0 ) + // contextMenu.takeItem( 0 ); + + // items.forEach( function(item) { contextMenu.addItem( + // menuItemComponent.createObject( contextMenu, itemsMap[item] ) ) + // }) + // contextMenu.height = items.length * root.menuItemHeight + // } + //*/ + // color: "cyan" //root.highlight ? InputStyle.panelItemHighlight : root.primaryColor + + // MouseArea { + // anchors.fill: parent + // enabled: projectIsValid + // onClicked: openRequested() + // } + + // RowLayout { + // id: row + + // anchors.fill: parent + // anchors.leftMargin: root.itemMargin + // spacing: 0 + + // Item { + // id: textContainer + + // height: root.height + // Layout.fillWidth: true + + // Text { + // id: mainText + + // text: "Ahoj" //__inputUtils.formatProjectName( projectDisplayName ) + // height: textContainer.height/2 + // width: textContainer.width + // font.pixelSize: 20 //InputStyle.fontPixelSizeNormal + // color: "grey" /*if (root.highlight) root.primaryColor + // else if (!projectIsValid) InputStyle.panelBackgroundDark + // else root.secondaryColor*/ + // horizontalAlignment: Text.AlignLeft + // verticalAlignment: Text.AlignBottom + // elide: Text.ElideLeft + // } + + // Text { + // id: secondaryText + + // visible: !projectIsPending + // height: textContainer.height/2 + // text: projectDescription + // anchors.right: parent.right + // anchors.bottom: parent.bottom + // anchors.left: parent.left + // anchors.top: mainText.bottom + // font.pixelSize: 20 //InputStyle.fontPixelSizeSmall + // color: "orange" // root.highlight ? root.primaryColor : InputStyle.panelBackgroundDark + // horizontalAlignment: Text.AlignLeft + // verticalAlignment: Text.AlignTop + // elide: Text.ElideRight + // } + + //// ProgressBar { + //// id: progressBar + + //// property real itemHeight: 10 //InputStyle.rowHeightSmall + + //// anchors.top: mainText.bottom + //// height: itemHeight + //// width: secondaryText.width + //// value: projectSyncProgress + //// visible: projectIsPending + + //// background: Rectangle { + //// implicitWidth: parent.width + //// implicitHeight: progressBar.itemHeight + //// color: "blue" //InputStyle.panelBackgroundLight + //// } + + //// contentItem: Item { + //// implicitWidth: parent.width + //// implicitHeight: progressBar.itemHeight + + //// Rectangle { + //// width: progressBar.visualPosition * parent.width + //// height: parent.height + //// color: "brown" //InputStyle.fontColor + //// } + //// } + //// } + // } + + // Item { + // id: statusIconContainer + + // //property string iconSource: getStatusIcon() + + // //visible: iconSource !== "" + // Layout.preferredWidth: root.height + // height: root.height + + // Image { + // id: statusIcon + + // anchors.centerIn: parent + // //source: statusIconContainer.iconSource + // height: root.iconSize + // width: height + // sourceSize.width: width + // sourceSize.height: height + // fillMode: Image.PreserveAspectFit + // } + + // ColorOverlay { + // anchors.fill: statusIcon + // source: statusIcon + // color: root.iconColor + // } + + // MouseArea { + // anchors.fill: parent + // onClicked: { + // if ( projectRemoteError ) { + // __inputUtils.showNotification( qsTr( "Could not synchronize project, please make sure you are logged in and have sufficient rights." ) ) + // return + // } + // if ( projectIsPending ) + // stopSyncRequested() + // else if ( !projectIsMergin ) + // migrateRequested() + // else + // syncRequested() + // } + // } + // } + + // Item { + // id: moreMenuContainer + + // Layout.preferredWidth: root.height + // height: root.height + + // Image { + // id: moreMenuIcon + + // anchors.centerIn: parent + // //source: InputStyle.moreMenuIcon + // height: root.iconSize + // width: height + // sourceSize.width: width + // sourceSize.height: height + // fillMode: Image.PreserveAspectFit + // } + + // ColorOverlay { + // anchors.fill: moreMenuIcon + // source: moreMenuIcon + // color: root.iconColor + // } + + // MouseArea { + // anchors.fill: parent + // onClicked: { + // fillMoreMenu() + // contextMenu.open() + // } + // } + // } + // } + + // Rectangle { // border line + // color: "white" //InputStyle.panelBackground2 + // width: root.width + // height: root.borderWidth + // anchors.bottom: parent.bottom + // } + ///* + // // More Menu + // Menu { + // id: contextMenu + + // width: Math.min( root.width, 300 * __dp ) + // leftMargin: Math.max( root.width - width, 0 ) + // z: 100 + + // enter: Transition { + // ParallelAnimation { + // NumberAnimation { property: "opacity"; from: 0; to: 1.0; duration: 100 } + // } + // } + // exit: Transition { + // ParallelAnimation { + // NumberAnimation { property: "opacity"; from: 1.0; to: 0; duration: 100 } + // } + // } + + // //! sets y-offset either above or below related item according relative position to end of the list + // onAboutToShow: { + // let itemRelativeY = parent.y - root.viewContentY + // if ( itemRelativeY + contextMenu.height >= root.viewHeight ) + // contextMenu.y = -contextMenu.height + parent.height / 3 + // else + // contextMenu.y = ( parent.height * 2 ) / 3 + // } + // } + + // Component { + // id: menuItemComponent + + // MenuItem { + // id: menuItem + + // property string name: "" + // property var callback: function cb() {} // default callback + // property string iconSource: "" + + // height: root.menuItemHeight + + // ExtendedMenuItem { + // height: parent.height + // rowHeight: parent.height * 0.8 + // width: parent.width + // contentText: menuItem.name + // imageSource: menuItem.iconSource + // overlayImage: true + // } + + // onClicked: callback() + // } + // }*/ +} diff --git a/gallery/qml.qrc b/gallery/qml.qrc index 14840713c..e34f15175 100644 --- a/gallery/qml.qrc +++ b/gallery/qml.qrc @@ -38,5 +38,6 @@ ../app/qml/components/MMMenuDrawer.qml ../app/qml/components/MMToolbarMenuButton.qml ../app/qml/components/MMToolbarLongButton.qml + qml/pages/ProjectItemsPage.qml diff --git a/gallery/qml/Main.qml b/gallery/qml/Main.qml index 738e82116..03272de3b 100644 --- a/gallery/qml/Main.qml +++ b/gallery/qml/Main.qml @@ -140,6 +140,10 @@ ApplicationWindow { title: "Toolbars" source: "ToolbarPage.qml" } + ListElement { + title: "Project items" + source: "ProjectItemsPage.qml" + } } ScrollIndicator.vertical: ScrollIndicator {} diff --git a/gallery/qml/pages/ProjectItemsPage.qml b/gallery/qml/pages/ProjectItemsPage.qml new file mode 100644 index 000000000..0725b991d --- /dev/null +++ b/gallery/qml/pages/ProjectItemsPage.qml @@ -0,0 +1,32 @@ +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +import QtQuick +import QtQuick.Controls +import "../../app/qmlV2/component" + +Page { + id: pane + + MMProjectItem { + width: 300 + anchors.horizontalCenter: parent.horizontalCenter + anchors.top: parent.top + anchors.topMargin: 20 + highlight: true + } + + MMProjectItem { + width: 300 + anchors.horizontalCenter: parent.horizontalCenter + anchors.top: parent.top + anchors.topMargin: 200 + highlight: false + } +}