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
+ }
+}