diff --git a/assets/images/filter.png b/assets/images/filter.png
new file mode 100644
index 0000000..33793c6
Binary files /dev/null and b/assets/images/filter.png differ
diff --git a/qml.qrc b/qml.qrc
index 3e0d196..45a6abe 100644
--- a/qml.qrc
+++ b/qml.qrc
@@ -77,6 +77,7 @@
assets/images/eye.png
assets/images/eye_slash.png
assets/images/file.png
+ assets/images/filter.png
assets/images/grid.png
assets/images/heart.png
assets/images/image.png
diff --git a/qml/components/ProductDialog.qml b/qml/components/ProductDialog.qml
index f8d1208..0dcd8a8 100644
--- a/qml/components/ProductDialog.qml
+++ b/qml/components/ProductDialog.qml
@@ -3,6 +3,8 @@ import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12
import Qt.labs.platform 1.1 // FileDialog
+import FontAwesome 1.0
+
import "." as NeroshopComponents
Popup {
@@ -22,14 +24,69 @@ Popup {
background: Rectangle {
radius: 8
color: (NeroshopComponents.Style.darkTheme) ? (NeroshopComponents.Style.themeName == "PurpleDust" ? "#0e0e11" : "#101010") : "#f0f0f0"
+
+ // header
+ Rectangle {
+ id: titleBar
+ color: "#202020"
+ height: 40
+ width: parent.width
+ anchors.left: parent.left
+ anchors.right: parent.right
+ radius: 6
+
+ // Rounded top corners
+ Rectangle {
+ anchors.left: parent.left
+ anchors.right: parent.right
+ anchors.bottom: parent.bottom
+ height: parent.height / 2
+ color: parent.color
+ }
+
+ Label {
+ text: "Add item"
+ color: "#ffffff"
+ font.bold: true
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.verticalCenter: parent.verticalCenter
+ }
+
+ Button {
+ id: closeButton
+ width: 25
+ height: this.width
+
+ anchors.verticalCenter: titleBar.verticalCenter
+ anchors.right: titleBar.right
+ anchors.rightMargin: 10
+ text: qsTr(FontAwesome.xmark)
+ contentItem: Text {
+ text: closeButton.text
+ color: "#ffffff"
+ font.bold: true
+ font.family: FontAwesome.fontFamily
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ }
+ background: Rectangle {
+ color: "#ff4d4d"
+ radius: 100
+ }
+ onClicked: {
+ productDialog.close()
+ mainScrollView.ScrollBar.vertical.position = 0.0 // reset scrollbar
+ }
+ }
+ }
}
contentItem: ScrollView {
id: mainScrollView
anchors.fill: parent
- anchors.topMargin: 20; anchors.bottomMargin: anchors.topMargin////anchors.margins: 20
+ anchors.topMargin: titleBar.height + 20; anchors.bottomMargin: 20//anchors.topMargin////anchors.margins: 20
clip: true
- ScrollBar.vertical.policy: ScrollBar.AsNeeded
+ ScrollBar.vertical.policy: ScrollBar.AlwaysOn//AsNeeded
ColumnLayout {
width: productDialog.availableWidth; height: productDialog.availableHeight
spacing: 30
@@ -41,7 +98,7 @@ Popup {
Column {
spacing: productDialog.titleSpacing
Text {
- text: "Product name"
+ text: "Name / Title"
color: productDialog.palette.text
font.bold: true
}
@@ -124,11 +181,34 @@ Popup {
Column {
spacing: productDialog.titleSpacing
- Text {
- text: "Quantity"
- color: productDialog.palette.text
- font.bold: true
- //visible: false
+ Row {
+ spacing: 10
+ Text {
+ text: qsTr("Quantity")
+ color: productDialog.palette.text
+ font.bold: true
+ }
+ Text {
+ text: qsTr(FontAwesome.circleInfo)
+ color: productDialog.optTextColor
+ font.bold: true
+ //font.pointSize:
+ anchors.verticalCenter: parent.children[0].verticalCenter
+ property bool hovered: false
+ NeroshopComponents.Hint {
+ x: parent.width + 10; y: ((parent.height - height) / 2) - 3
+ visible: parent.hovered
+ height: contentHeight + 20; width: contentWidth + 20
+ text: qsTr("The total number of items in stock")
+ pointer.visible: false;// delay: 0
+ }
+ MouseArea {
+ anchors.fill: parent
+ hoverEnabled: true
+ onEntered: parent.hovered = true
+ onExited: parent.hovered = false
+ }
+ }
}
TextField {
@@ -250,298 +330,298 @@ Popup {
}
}
- Row {
- spacing: 5
- TextField {
- id: productCodeField
- width: 500 - parent.children[1].width - parent.spacing; height: 50
- placeholderText: qsTr("Enter product code")
- color: productDialog.inputTextColor
- selectByMouse: true
- background: Rectangle {
- color: "transparent"
- border.color: productDialog.inputBorderColor
- border.width: parent.activeFocus ? 2 : 1
- radius: productDialog.inputRadius
- }
- }
- NeroshopComponents.ComboBox {
- id: productCodeType
- height: parent.children[0].height//Layout.preferredWidth: 100; Layout.preferredHeight: parent.children[0].height
- model: ["EAN", "ISBN", "JAN", "SKU", "UPC"] // default is UPC (each code will be validated before product is listed)
- Component.onCompleted: currentIndex = find("UPC")
- radius: productDialog.inputRadius
- color: productDialog.inputBaseColor
- textColor: productDialog.inputTextColor
- }
- }
+ Row {
+ spacing: 5
+ TextField {
+ id: productCodeField
+ width: 500 - parent.children[1].width - parent.spacing; height: 50
+ placeholderText: qsTr("Enter product code")
+ color: productDialog.inputTextColor
+ selectByMouse: true
+ background: Rectangle {
+ color: "transparent"
+ border.color: productDialog.inputBorderColor
+ border.width: parent.activeFocus ? 2 : 1
+ radius: productDialog.inputRadius
+ }
}
- }
- // Product categories
- Item {
- //Layout.row:
- Layout.alignment: Qt.AlignHCenter
- Layout.preferredWidth: childrenRect.width
- Layout.preferredHeight: childrenRect.height
- function getCategoryStringList() {
- let categoryStringList = []
- let categories = Backend.getCategoryList(true)
- for(let i = 0; i < categories.length; i++) {
- categoryStringList[i] = categories[i].name//console.log(parent.parent.parent.categoryStringList[i])//console.log(categories[i].name)
- }
- return categoryStringList;
+ NeroshopComponents.ComboBox {
+ id: productCodeType
+ height: parent.children[0].height//Layout.preferredWidth: 100; Layout.preferredHeight: parent.children[0].height
+ model: ["EAN", "ISBN", "JAN", "SKU", "UPC"] // default is UPC (each code will be validated before product is listed)
+ Component.onCompleted: currentIndex = find("UPC")
+ radius: productDialog.inputRadius
+ color: productDialog.inputBaseColor
+ textColor: productDialog.inputTextColor
}
+ }
+ }
+ }
+ // Product categories
+ Item {
+ //Layout.row:
+ Layout.alignment: Qt.AlignHCenter
+ Layout.preferredWidth: childrenRect.width
+ Layout.preferredHeight: childrenRect.height
+ function getCategoryStringList() {
+ let categoryStringList = []
+ let categories = Backend.getCategoryList(true)
+ for(let i = 0; i < categories.length; i++) {
+ categoryStringList[i] = categories[i].name//console.log(parent.parent.parent.categoryStringList[i])//console.log(categories[i].name)
+ }
+ return categoryStringList;
+ }
- Column {
- spacing: productDialog.titleSpacing
- Text {
- text: "Category"
- color: productDialog.palette.text
- font.bold: true
- }
+ Column {
+ spacing: productDialog.titleSpacing
+ Text {
+ text: "Category"
+ color: productDialog.palette.text
+ font.bold: true
+ }
- Row {
- spacing: 5
- NeroshopComponents.ComboBox {
- id: productCategoryBox
- width: addSubCategoryButton.visible ? (500 - addSubCategoryButton.width - parent.spacing) : 500; height: 50
- model: parent.parent.parent.getCategoryStringList()
- Component.onCompleted: {
- currentIndex = find("Miscellaneous")
- }
- function reset() {
- let subcategories = Backend.getSubCategoryList(Backend.getCategoryIdByName(productCategoryBox.currentText), true)
- addSubCategoryButton.visible = (subcategories.length > 0)
- subCategoryRepeater.model = 0 // reset
- }
- onActivated: {
- productCategoryBox.reset()
- }
- radius: productDialog.inputRadius
- color: productDialog.inputBaseColor
- textColor: productDialog.inputTextColor
- }
- Button {
- id: addSubCategoryButton
- width: 50; height: 50
- text: qsTr("+")
- visible: Backend.hasSubCategory(Backend.getCategoryIdByName(productCategoryBox.currentText))
- background: Rectangle {
- color: parent.hovered ? "#698b22" : "#506a1a"//"#605185"
- radius: productDialog.inputRadius
- }
- contentItem: Text {
- text: parent.text
- color: "#ffffff"
- verticalAlignment: Text.AlignVCenter
- horizontalAlignment: Text.AlignHCenter
- }
- onClicked: {
- let subcategories = Backend.getSubCategoryList(Backend.getCategoryIdByName(productCategoryBox.currentText), true)
- let max_subcategories = Math.min(2, subcategories.length)
- if(subCategoryRepeater.count == max_subcategories) {
- console.log("Cannot add no more than " + max_subcategories + " subcategories")
- return
- }
- subCategoryRepeater.model = subCategoryRepeater.model + 1
- }
- }
+ Row {
+ spacing: 5
+ NeroshopComponents.ComboBox {
+ id: productCategoryBox
+ width: addSubCategoryButton.visible ? (500 - addSubCategoryButton.width - parent.spacing) : 500; height: 50
+ model: parent.parent.parent.getCategoryStringList()
+ Component.onCompleted: {
+ currentIndex = find("Miscellaneous")
}
- }
- }
- // Subcategories (will be determined based on selected categories)
- Item {
- id: subCategoryItem
- Layout.alignment: Qt.AlignHCenter
- Layout.preferredWidth: childrenRect.width
- Layout.preferredHeight: childrenRect.height
- visible: (subCategoryRepeater.count > 0)//Backend.hasSubCategory(Backend.getCategoryIdByName(productCategoryBox.currentText))
-
- function getSubCategoryStringList() {
- let subCategoryStringList = []
- let subcategories = Backend.getSubCategoryList(Backend.getCategoryIdByName(productCategoryBox.currentText), true)
- for(let i = 0; i < subcategories.length; i++) {
- subCategoryStringList[i] = subcategories[i].name//console.log(parent.parent.parent.categoryStringList[i])//console.log(categories[i].name)
- }
- return subCategoryStringList;
- }
-
- Column {
- spacing: productDialog.titleSpacing
- Text {
- text: "Subcategory"
- color: productDialog.palette.text
- font.bold: true
+ function reset() {
+ let subcategories = Backend.getSubCategoryList(Backend.getCategoryIdByName(productCategoryBox.currentText), true)
+ addSubCategoryButton.visible = (subcategories.length > 0)
+ subCategoryRepeater.model = 0 // reset
}
-
- Repeater {
- id: subCategoryRepeater
- model: 0
- delegate: Row {
- spacing: 5
- NeroshopComponents.ComboBox {
- id: productSubCategoryBox
- width: removeSubCategoryButton.visible ? (500 - removeSubCategoryButton.width - parent.spacing) : 500; height: 50
- model: parent.parent.parent.getSubCategoryStringList()
- currentIndex: 0
- radius: productDialog.inputRadius
- color: productDialog.inputBaseColor
- textColor: productDialog.inputTextColor
- }
- Button {
- id: removeSubCategoryButton
- width: 50; height: 50
- text: qsTr("x")
- background: Rectangle {
- color: parent.hovered ? "#b22222" : "#921c1c"
- radius: productDialog.inputRadius
- }
- contentItem: Text {
- text: parent.text
- color: "#ffffff"
- verticalAlignment: Text.AlignVCenter
- horizontalAlignment: Text.AlignHCenter
- }
- onClicked: {
- subCategoryRepeater.model = subCategoryRepeater.model - 1
- }
- }
- } // Row
+ onActivated: {
+ productCategoryBox.reset()
}
+ radius: productDialog.inputRadius
+ color: productDialog.inputBaseColor
+ textColor: productDialog.inputTextColor
}
- }
- // Weight
- Item {
- //Layout.row:
- Layout.alignment: Qt.AlignHCenter
- Layout.preferredWidth: childrenRect.width
- Layout.preferredHeight: childrenRect.height
-
- Column {
- spacing: productDialog.titleSpacing
- Row {
- spacing: 10
- Text {
- text: "Weight"
- color: productDialog.palette.text
- font.bold: true
- }
- Text {
- text: "(OPTIONAL)"
- color: productDialog.optTextColor
- font.bold: true
- font.pointSize: 8
- anchors.verticalCenter: parent.children[0].verticalCenter
- }
+ Button {
+ id: addSubCategoryButton
+ width: 50; height: 50
+ text: qsTr("+")
+ visible: Backend.hasSubCategory(Backend.getCategoryIdByName(productCategoryBox.currentText))
+ background: Rectangle {
+ color: parent.hovered ? "#698b22" : "#506a1a"//"#605185"
+ radius: productDialog.inputRadius
}
-
- Row {
- spacing: 5
- TextField {
- id: productWeightField
- width: 500 - parent.children[1].width - parent.spacing; height: 50
- placeholderText: qsTr("Enter weight")
- color: productDialog.inputTextColor
- selectByMouse: true
- validator: RegExpValidator{ regExp: new RegExp("^-?[0-9]+(\\.[0-9]{1," + 8 + "})?$") }
- background: Rectangle {
- color: "transparent"
- border.color: productDialog.inputBorderColor
- border.width: parent.activeFocus ? 2 : 1
- radius: productDialog.inputRadius
- }
- }
- NeroshopComponents.ComboBox {
- id: weightMeasurementUnit
- height: parent.children[0].height
- model: ["kg", "lb"] // default is kg (every unit of measurement will be converted to kg)
- Component.onCompleted: currentIndex = find("kg")
- radius: productDialog.inputRadius
- color: productDialog.inputBaseColor
- textColor: productDialog.inputTextColor
+ contentItem: Text {
+ text: parent.text
+ color: "#ffffff"
+ verticalAlignment: Text.AlignVCenter
+ horizontalAlignment: Text.AlignHCenter
+ }
+ onClicked: {
+ let subcategories = Backend.getSubCategoryList(Backend.getCategoryIdByName(productCategoryBox.currentText), true)
+ let max_subcategories = Math.min(2, subcategories.length)
+ if(subCategoryRepeater.count == max_subcategories) {
+ console.log("Cannot add no more than " + max_subcategories + " subcategories")
+ return
}
+ subCategoryRepeater.model = subCategoryRepeater.model + 1
}
}
- }
- // Size
- /*Item {
- //Layout.row:
- Layout.alignment: Qt.AlignHCenter
- Layout.preferredWidth: childrenRect.width
- Layout.preferredHeight: childrenRect.height
+ }
+ }
+ }
+ // Subcategories (will be determined based on selected categories)
+ Item {
+ id: subCategoryItem
+ Layout.alignment: Qt.AlignHCenter
+ Layout.preferredWidth: childrenRect.width
+ Layout.preferredHeight: childrenRect.height
+ visible: (subCategoryRepeater.count > 0)//Backend.hasSubCategory(Backend.getCategoryIdByName(productCategoryBox.currentText))
- Column {
- spacing: productDialog.titleSpacing
- Row {
- spacing: 10
- Text {
- text: "Size"
- color: productDialog.palette.text
- font.bold: true
+ function getSubCategoryStringList() {
+ let subCategoryStringList = []
+ let subcategories = Backend.getSubCategoryList(Backend.getCategoryIdByName(productCategoryBox.currentText), true)
+ for(let i = 0; i < subcategories.length; i++) {
+ subCategoryStringList[i] = subcategories[i].name//console.log(parent.parent.parent.categoryStringList[i])//console.log(categories[i].name)
+ }
+ return subCategoryStringList;
+ }
+
+ Column {
+ spacing: productDialog.titleSpacing
+ Text {
+ text: "Subcategory"
+ color: productDialog.palette.text
+ font.bold: true
+ }
+
+ Repeater {
+ id: subCategoryRepeater
+ model: 0
+ delegate: Row {
+ spacing: 5
+ NeroshopComponents.ComboBox {
+ id: productSubCategoryBox
+ width: removeSubCategoryButton.visible ? (500 - removeSubCategoryButton.width - parent.spacing) : 500; height: 50
+ model: parent.parent.parent.getSubCategoryStringList()
+ currentIndex: 0
+ radius: productDialog.inputRadius
+ color: productDialog.inputBaseColor
+ textColor: productDialog.inputTextColor
+ }
+ Button {
+ id: removeSubCategoryButton
+ width: 50; height: 50
+ text: qsTr("x")
+ background: Rectangle {
+ color: parent.hovered ? "#b22222" : "#921c1c"
+ radius: productDialog.inputRadius
}
- Text {
- text: "(OPTIONAL)"
- color: productDialog.optTextColor
- font.bold: true
- font.pointSize: 8
- anchors.verticalCenter: parent.children[0].verticalCenter
+ contentItem: Text {
+ text: parent.text
+ color: "#ffffff"
+ verticalAlignment: Text.AlignVCenter
+ horizontalAlignment: Text.AlignHCenter
}
- }
-
- Row {
- spacing: 5
- TextField {
- id: productSizeField
- width: 500; height: 50
- placeholderText: qsTr("Enter size")
- color: productDialog.inputTextColor
- selectByMouse: true
- background: Rectangle {
- color: "transparent"
- border.color: productDialog.inputBorderColor
- border.width: parent.activeFocus ? 2 : 1
- radius: productDialog.inputRadius
- }
+ onClicked: {
+ subCategoryRepeater.model = subCategoryRepeater.model - 1
}
- //ComboBox
}
- }
- }*/
- // Variations/Attributes (i.e. Color, Size, Type, Model, etc. options to choose from - optional)
- // Product location (ship to and ship from)
- Item {
- Layout.alignment: Qt.AlignHCenter
- Layout.preferredWidth: childrenRect.width
- Layout.preferredHeight: childrenRect.height
- property var countriesModel: ["Afghanistan", "Albania", "Algeria", "Andorra", "Angola", "Antigua & Deps", "Argentina", "Armenia", "Australia", "Austria", "Azerbaijan", "Bahamas", "Bahrain", "Bangladesh", "Barbados", "Belarus", "Belgium", "Belize", "Benin", "Bermuda", "Bhutan", "Bolivia", "Bosnia Herzegovina", "Botswana", "Brazil", "Brunei", "Bulgaria", "Burkina", "Burundi", "Cambodia", "Cameroon", "Canada", "Cape Verde", "Central African Rep", "Chad", "Chile", "China", "Colombia", "Comoros", "Congo", "Congo (Democratic Rep)", "Costa Rica", "Croatia", "Cuba", "Cyprus", "Czech Republic", "Denmark", "Djibouti", "Dominica", "Dominican Republic", "East Timor", "Ecuador", "Egypt", "El Salvador", "Equatorial Guinea", "Eritrea", "Estonia", "Eswatini", "Ethiopia", "Fiji", "Finland", "France", "Gabon", "Gambia", "Georgia", "Germany", "Ghana", "Greece", "Grenada", "Guatemala", "Guinea", "Guinea-Bissau", "Guyana", "Haiti", "Honduras", "Hungary", "Iceland", "India", "Indonesia", "Iran", "Iraq", "Ireland (Republic)", "Israel", "Italy", "Ivory Coast", "Jamaica", "Japan", "Jordan", "Kazakhstan", "Kenya", "Kiribati", "Korea North", "Korea South", "Kosovo", "Kuwait", "Kyrgyzstan", "Laos", "Latvia", "Lebanon", "Lesotho", "Liberia", "Libya", "Liechtenstein", "Lithuania", "Luxembourg", "Macedonia", "Madagascar", "Malawi", "Malaysia", "Maldives", "Mali", "Malta", "Marshall Islands", "Mauritania", "Mauritius", "Mexico", "Micronesia", "Moldova", "Monaco", "Mongolia", "Montenegro", "Morocco", "Mozambique", "Myanmar", "Namibia", "Nauru", "Nepal", "Netherlands", "New Zealand", "Nicaragua", "Niger", "Nigeria", "Norway", "Oman", "Pakistan", "Palau", "Palestine", "Panama", "Papua New Guinea", "Paraguay", "Peru", "Philippines", "Poland", "Portugal", "Qatar", "Romania", "Russian Federation", "Rwanda", "St Kitts & Nevis", "St Lucia", "Saint Vincent & the Grenadines", "Samoa", "San Marino", "Sao Tome & Principe", "Saudi Arabia", "Senegal", "Serbia", "Seychelles", "Sierra Leone", "Singapore", "Slovakia", "Slovenia", "Solomon Islands", "Somalia", "South Africa", "South Sudan", "Spain", "Sri Lanka", "Sudan", "Suriname", "Sweden", "Switzerland", "Syria", "Taiwan", "Tajikistan", "Tanzania", "Thailand", "Togo", "Tonga", "Trinidad & Tobago", "Tunisia", "Turkey", "Turkmenistan", "Tuvalu", "Uganda", "Ukraine", "United Arab Emirates", "United Kingdom", "United States", "Unspecified", "Uruguay", "Uzbekistan", "Vanuatu", "Vatican City", "Venezuela", "Vietnam", "Yemen", "Zambia", "Zimbabwe", "Worldwide",]
+ } // Row
+ }
+ }
+ }
+ // Weight
+ Item {
+ //Layout.row:
+ Layout.alignment: Qt.AlignHCenter
+ Layout.preferredWidth: childrenRect.width
+ Layout.preferredHeight: childrenRect.height
- Column {
- spacing: productDialog.titleSpacing
- Text {
- text: "Location"
- color: productDialog.palette.text
- font.bold: true
- }
+ Column {
+ spacing: productDialog.titleSpacing
+ Row {
+ spacing: 10
+ Text {
+ text: "Weight"
+ color: productDialog.palette.text
+ font.bold: true
+ }
+ Text {
+ text: "(OPTIONAL)"
+ color: productDialog.optTextColor
+ font.bold: true
+ font.pointSize: 8
+ anchors.verticalCenter: parent.children[0].verticalCenter
+ }
+ }
- NeroshopComponents.ComboBox {
- id: productLocationBox
- width: 500; height: 50
- model: parent.parent.countriesModel
- Component.onCompleted: {
- contentItem.selectByMouse = true
- currentIndex = find("Unspecified")//find("Worldwide")
- }
- editable: true
- onAccepted: {
- if(find(editText) === -1)
- model.append({text: editText})
- }
+ Row {
+ spacing: 5
+ TextField {
+ id: productWeightField
+ width: 500 - parent.children[1].width - parent.spacing; height: 50
+ placeholderText: qsTr("Enter weight")
+ color: productDialog.inputTextColor
+ selectByMouse: true
+ validator: RegExpValidator{ regExp: new RegExp("^-?[0-9]+(\\.[0-9]{1," + 8 + "})?$") }
+ background: Rectangle {
+ color: "transparent"
+ border.color: productDialog.inputBorderColor
+ border.width: parent.activeFocus ? 2 : 1
radius: productDialog.inputRadius
- color: productDialog.inputBaseColor
- textColor: productDialog.inputTextColor
}
}
- }
+ NeroshopComponents.ComboBox {
+ id: weightMeasurementUnit
+ height: parent.children[0].height
+ model: ["kg", "lb"] // default is kg (every unit of measurement will be converted to kg)
+ Component.onCompleted: currentIndex = find("kg")
+ radius: productDialog.inputRadius
+ color: productDialog.inputBaseColor
+ textColor: productDialog.inputTextColor
+ }
+ }
+ }
+ }
+ // Size
+ /*Item {
+ //Layout.row:
+ Layout.alignment: Qt.AlignHCenter
+ Layout.preferredWidth: childrenRect.width
+ Layout.preferredHeight: childrenRect.height
+
+ Column {
+ spacing: productDialog.titleSpacing
+ Row {
+ spacing: 10
+ Text {
+ text: "Size"
+ color: productDialog.palette.text
+ font.bold: true
+ }
+ Text {
+ text: "(OPTIONAL)"
+ color: productDialog.optTextColor
+ font.bold: true
+ font.pointSize: 8
+ anchors.verticalCenter: parent.children[0].verticalCenter
+ }
+ }
+
+ Row {
+ spacing: 5
+ TextField {
+ id: productSizeField
+ width: 500; height: 50
+ placeholderText: qsTr("Enter size")
+ color: productDialog.inputTextColor
+ selectByMouse: true
+ background: Rectangle {
+ color: "transparent"
+ border.color: productDialog.inputBorderColor
+ border.width: parent.activeFocus ? 2 : 1
+ radius: productDialog.inputRadius
+ }
+ }
+ //ComboBox
+ }
+ }
+ }*/
+ // Variations/Attributes (i.e. Color, Size, Type, Model, etc. options to choose from - optional)
+ // Product location (ship to and ship from)
+ Item {
+ Layout.alignment: Qt.AlignHCenter
+ Layout.preferredWidth: childrenRect.width
+ Layout.preferredHeight: childrenRect.height
+ property var countriesModel: ["Afghanistan", "Albania", "Algeria", "Andorra", "Angola", "Antigua & Deps", "Argentina", "Armenia", "Australia", "Austria", "Azerbaijan", "Bahamas", "Bahrain", "Bangladesh", "Barbados", "Belarus", "Belgium", "Belize", "Benin", "Bermuda", "Bhutan", "Bolivia", "Bosnia Herzegovina", "Botswana", "Brazil", "Brunei", "Bulgaria", "Burkina", "Burundi", "Cambodia", "Cameroon", "Canada", "Cape Verde", "Central African Rep", "Chad", "Chile", "China", "Colombia", "Comoros", "Congo", "Congo (Democratic Rep)", "Costa Rica", "Croatia", "Cuba", "Cyprus", "Czech Republic", "Denmark", "Djibouti", "Dominica", "Dominican Republic", "East Timor", "Ecuador", "Egypt", "El Salvador", "Equatorial Guinea", "Eritrea", "Estonia", "Eswatini", "Ethiopia", "Fiji", "Finland", "France", "Gabon", "Gambia", "Georgia", "Germany", "Ghana", "Greece", "Grenada", "Guatemala", "Guinea", "Guinea-Bissau", "Guyana", "Haiti", "Honduras", "Hungary", "Iceland", "India", "Indonesia", "Iran", "Iraq", "Ireland (Republic)", "Israel", "Italy", "Ivory Coast", "Jamaica", "Japan", "Jordan", "Kazakhstan", "Kenya", "Kiribati", "Korea North", "Korea South", "Kosovo", "Kuwait", "Kyrgyzstan", "Laos", "Latvia", "Lebanon", "Lesotho", "Liberia", "Libya", "Liechtenstein", "Lithuania", "Luxembourg", "Macedonia", "Madagascar", "Malawi", "Malaysia", "Maldives", "Mali", "Malta", "Marshall Islands", "Mauritania", "Mauritius", "Mexico", "Micronesia", "Moldova", "Monaco", "Mongolia", "Montenegro", "Morocco", "Mozambique", "Myanmar", "Namibia", "Nauru", "Nepal", "Netherlands", "New Zealand", "Nicaragua", "Niger", "Nigeria", "Norway", "Oman", "Pakistan", "Palau", "Palestine", "Panama", "Papua New Guinea", "Paraguay", "Peru", "Philippines", "Poland", "Portugal", "Qatar", "Romania", "Russian Federation", "Rwanda", "St Kitts & Nevis", "St Lucia", "Saint Vincent & the Grenadines", "Samoa", "San Marino", "Sao Tome & Principe", "Saudi Arabia", "Senegal", "Serbia", "Seychelles", "Sierra Leone", "Singapore", "Slovakia", "Slovenia", "Solomon Islands", "Somalia", "South Africa", "South Sudan", "Spain", "Sri Lanka", "Sudan", "Suriname", "Sweden", "Switzerland", "Syria", "Taiwan", "Tajikistan", "Tanzania", "Thailand", "Togo", "Tonga", "Trinidad & Tobago", "Tunisia", "Turkey", "Turkmenistan", "Tuvalu", "Uganda", "Ukraine", "United Arab Emirates", "United Kingdom", "United States", "Unspecified", "Uruguay", "Uzbekistan", "Vanuatu", "Vatican City", "Venezuela", "Vietnam", "Yemen", "Zambia", "Zimbabwe", "Worldwide",]
+
+ Column {
+ spacing: productDialog.titleSpacing
+ Text {
+ text: "Location"
+ color: productDialog.palette.text
+ font.bold: true
+ }
+
+ NeroshopComponents.ComboBox {
+ id: productLocationBox
+ width: 500; height: 50
+ model: parent.parent.countriesModel
+ Component.onCompleted: {
+ contentItem.selectByMouse = true
+ currentIndex = find("Unspecified")//find("Worldwide")
+ }
+ editable: true
+ onAccepted: {
+ if(find(editText) === -1)
+ model.append({text: editText})
+ }
+ radius: productDialog.inputRadius
+ color: productDialog.inputBaseColor
+ textColor: productDialog.inputTextColor
+ }
+ }
+ }
//Product description and bullet points
Item {
//Layout.row:
@@ -625,7 +705,7 @@ Popup {
contentWidth: (210 * productImageRepeater.count) + (5 * (productImageRepeater.count - 1))//<- 5 is the Flow.spacing//; contentHeight: 210//<- contentHeight is not needed unless a newline is supported
clip: true
ScrollBar.horizontal: ScrollBar {
- policy: ScrollBar.AsNeeded
+ policy: ScrollBar.AlwaysOn//AsNeeded
}
Flow {
width: parent.contentWidth; height: parent.height//anchors.fill: parent// Note: Flow width must be large enough to fit all items horizontally so that there won't be a need to move an item to a newline
@@ -662,6 +742,44 @@ Popup {
//if(this.status == Image.Null) console.log("No image has been set" + parent.parent.index)
}
}
+ // Position the close button
+ Button {
+ id: removeImageButton
+ anchors.right: parent.right
+ anchors.top: parent.top
+ anchors.margins: 8
+
+ width: 20; height: 20//32
+ text: qsTr(FontAwesome.xmark)
+ hoverEnabled: true
+ visible: (parent.children[0].status === Image.Ready)
+
+ contentItem: Text {
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ text: removeImageButton.text
+ color: removeImageButton.hovered ? "#ffffff" : "#000000"
+ font.bold: true
+ font.family: FontAwesome.fontFamily
+ }
+
+ background: Rectangle {
+ width: parent.width
+ height: parent.height
+ radius: 5//50
+ color: removeImageButton.hovered ? "firebrick" : "transparent"
+ opacity: 0.7
+ }
+
+ onClicked: {
+ parent.children[0].source = ""
+ }
+ MouseArea {
+ anchors.fill: parent
+ onPressed: mouse.accepted = false
+ cursorShape: Qt.PointingHandCursor
+ }
+ }
}
Button {
@@ -735,7 +853,7 @@ Popup {
id: listProductButton
width: 333.333333333; height: contentItem.contentHeight + 30
hoverEnabled: true
- text: qsTr("Add")
+ text: qsTr("Submit")
background: Rectangle {
color: parent.hovered ? "#698b22" : "#506a1a"
radius: productDialog.inputRadius
@@ -750,6 +868,12 @@ Popup {
// Check input fields to see if entered info is valid
// ...
//---------------------------------------
+ if(productNameField.text.length < 3) {
+ messageBox.text = qsTr("Product name is too short")
+ messageBox.open()
+ return; // exit function
+ }
+ //---------------------------------------
let subcategory_ids = []//let subcategories = []
for (let i = 0; i < subCategoryRepeater.count; i++) {
subcategory_ids.push(Backend.getSubCategoryIdByName(subCategoryRepeater.itemAt(i).children[0].currentText))//subcategories.push(subCategoryRepeater.itemAt(i).children[0].currentText)//console.log("Added subcategory: ", subcategories[i])
@@ -767,7 +891,12 @@ Popup {
let attributes = [];
let attribute_object = {};
if(productWeightField.text.length > 0 && Number(productWeightField.text) > 0.00) {
- attribute_object.weight = productWeightField.text
+ if(weightMeasurementUnit.currentText !== "kg") {
+ console.log("weight is in " + weightMeasurementUnit.currentText + ". Converting to kg ...")
+ attribute_object.weight = Backend.weightToKg(Number(productWeightField.text), weightMeasurementUnit.currentText)
+ } else {
+ attribute_object.weight = Number(productWeightField.text)
+ }
}
// Add attribute obj to list as long as its filled with properties
if (Object.keys(attribute_object).length > 0) {
@@ -799,7 +928,7 @@ Popup {
productNameField.text,
productDescriptionEdit.text,
attributes,
- productCodeField.text,
+ productCodeType.currentText.toLowerCase() + ":" + productCodeField.text,
Backend.getCategoryIdByName(productCategoryBox.currentText),
(subCategoryRepeater.count > 0) ? subcategory_ids : [], // subcategoryIds
productTagsField.tags(),
diff --git a/qml/pages/CatalogPage.qml b/qml/pages/CatalogPage.qml
index 3647247..e216097 100644
--- a/qml/pages/CatalogPage.qml
+++ b/qml/pages/CatalogPage.qml
@@ -75,47 +75,91 @@ Page {
}
//GroupBox {
// title: qsTr("Sort")
- // SortComboBox
- NeroshopComponents.ComboBox {
- id: sortByBox
+ Row {
anchors.right: parent.right
anchors.verticalCenter: viewToggle.verticalCenter
- width: 250
- model: ["None", "Latest", "Oldest", "Alphabetical order", "Price - Lowest", "Price - Highest"]
- Component.onCompleted: currentIndex = find("None")
- displayText: "Sort: " + currentText
- indicatorDoNotPassBorder: true
- onActivated: {
- if(currentIndex == find("None")) {
- catalogPage.model = Backend.sortBy(catalogPage.model, Enum.Sorting.SortByOldest)//Enum.Sorting.SortNone)
- settingsDialog.lastUsedListingSorting = Enum.Sorting.SortNone
+ spacing: 3
+ // Filter button
+ Button {
+ id: filterButton
+ text: qsTr("Filter")
+ //anchors.verticalCenter: parent.verticalCenter
+ //height: sortBox.height
+ checkable: true
+ checked: filterPopUp.visible
+ display: AbstractButton.IconOnly
+ icon.source: "qrc:/assets/images/filter.png"
+ icon.color: !this.checked ? "#605185" : "#ffffff"
+ background: Rectangle {
+ radius: 3
+ color: parent.checked ? "#605185" : "#e0e0e0"
}
- if(currentIndex == find("Oldest")) {
- catalogPage.model = Backend.sortBy(catalogPage.model, Enum.Sorting.SortByOldest)
- settingsDialog.lastUsedListingSorting = Enum.Sorting.SortByOldest
+ onClicked: {
+ filterPopUp.visible = true
}
- if(currentIndex == find("Latest")) {
- console.log("Showing most recent items")
- catalogPage.model = Backend.sortBy(catalogPage.model, Enum.Sorting.SortByMostRecent)
- settingsDialog.lastUsedListingSorting = Enum.Sorting.SortByMostRecent
+
+ Popup {
+ id: filterPopUp
+ visible: false
+ x: (parent.width - width) / 2
+ y: parent.height + 1
+ width: 200
+ height: 300//implicitHeight: contentItem.implicitHeight
+
+ background: Rectangle {
+ radius: 5
+ color: "#e0e0e0"
+ }
+
+ contentItem: /*NeroshopComponents.FilterBox {*/Item {
+ Text {
+ text: qsTr("Coming soon!")
+ anchors.centerIn: parent
+ }
+ }
}
- if(currentIndex == find("Alphabetical order")) {
- catalogPage.model = Backend.sortBy(catalogPage.model, Enum.Sorting.SortByAlphabeticalOrder)
- settingsDialog.lastUsedListingSorting = Enum.Sorting.SortByAlphabeticalOrder
- }
- if(currentIndex == find("Price - Lowest")) {
- catalogPage.model = Backend.sortBy(catalogPage.model, Enum.Sorting.SortByPriceLowest)
- settingsDialog.lastUsedListingSorting = Enum.Sorting.SortByPriceLowest
- }
- if(currentIndex == find("Price - Highest")) {
- catalogPage.model = Backend.sortBy(catalogPage.model, Enum.Sorting.SortByPriceHighest)
- settingsDialog.lastUsedListingSorting = Enum.Sorting.SortByPriceHighest
+ }
+ // SortComboBox
+ NeroshopComponents.ComboBox {
+ id: sortBox
+ //anchors.verticalCenter: parent.verticalCenter
+ width: 250; height: viewToggle.height
+ model: ["None", "Latest", "Oldest", "Alphabetical order", "Price - Lowest", "Price - Highest"]
+ Component.onCompleted: currentIndex = find("None")
+ displayText: "Sort: " + currentText
+ indicatorDoNotPassBorder: true
+ onActivated: {
+ if(currentIndex == find("None")) {
+ catalogPage.model = Backend.sortBy(catalogPage.model, Enum.Sorting.SortByOldest)//Enum.Sorting.SortNone)
+ settingsDialog.lastUsedListingSorting = Enum.Sorting.SortNone
+ }
+ if(currentIndex == find("Oldest")) {
+ catalogPage.model = Backend.sortBy(catalogPage.model, Enum.Sorting.SortByOldest)
+ settingsDialog.lastUsedListingSorting = Enum.Sorting.SortByOldest
+ }
+ if(currentIndex == find("Latest")) {
+ console.log("Showing most recent items")
+ catalogPage.model = Backend.sortBy(catalogPage.model, Enum.Sorting.SortByMostRecent)
+ settingsDialog.lastUsedListingSorting = Enum.Sorting.SortByMostRecent
+ }
+ if(currentIndex == find("Alphabetical order")) {
+ catalogPage.model = Backend.sortBy(catalogPage.model, Enum.Sorting.SortByAlphabeticalOrder)
+ settingsDialog.lastUsedListingSorting = Enum.Sorting.SortByAlphabeticalOrder
+ }
+ if(currentIndex == find("Price - Lowest")) {
+ catalogPage.model = Backend.sortBy(catalogPage.model, Enum.Sorting.SortByPriceLowest)
+ settingsDialog.lastUsedListingSorting = Enum.Sorting.SortByPriceLowest
+ }
+ if(currentIndex == find("Price - Highest")) {
+ catalogPage.model = Backend.sortBy(catalogPage.model, Enum.Sorting.SortByPriceHighest)
+ settingsDialog.lastUsedListingSorting = Enum.Sorting.SortByPriceHighest
+ }
+ /*if(currentIndex == find("")) {
+ catalogPage.model = Backend.
+ }*/
}
- /*if(currentIndex == find("")) {
- catalogPage.model = Backend.
- }*/
}
- }
+ } // Row
} // Rectangle
StackLayout {
id: catalogStack
diff --git a/qml/pages/subpages/DashboardPage.qml b/qml/pages/subpages/DashboardPage.qml
index dad4561..78bd25f 100644
--- a/qml/pages/subpages/DashboardPage.qml
+++ b/qml/pages/subpages/DashboardPage.qml
@@ -257,7 +257,7 @@ Page {
Button {
id: addProductButton
////anchors.right: parent.right // <- uncomment if not enclosed in row
- text: qsTr("+ Add Product")
+ text: qsTr("+ Add Item")
width: 304/*inventoryManager.width*/; height: 100//width: 200; height: 100//width: 100; height: width
hoverEnabled: true
background: Rectangle {
@@ -409,7 +409,7 @@ Page {
id: removeProductsMessageBox
x: mainWindow.x + (mainWindow.width - this.width) / 2
y: mainWindow.y + (mainWindow.height - this.height) / 2
- title: qsTr("Remove product")
+ title: qsTr("Remove items")
text: qsTr("Are you sure you want to permanently remove the selected item(s)?")
buttonModel: ["No", "Yes"]
buttonRow.state: "centered"; buttonRow.width: 300 // buttons should fill the row width
diff --git a/src/core/price/currency_converter.cpp b/src/core/price/currency_converter.cpp
index d4271dd..4e235c8 100644
--- a/src/core/price/currency_converter.cpp
+++ b/src/core/price/currency_converter.cpp
@@ -17,7 +17,7 @@
std::string neroshop::Converter::json_string ("");
//-------------------------------------------------------
//-------------------------------------------------------
-double neroshop::Converter::to_kg(double amount, const std::string& unit_name) const {
+double neroshop::Converter::to_kg(double amount, const std::string& unit_name) {
if(neroshop::string::lower(unit_name) == "lb" || neroshop::string::lower(unit_name) == "lbs" || neroshop::string::lower(unit_name) == "pound") {return lb_to_kg(amount);}
return 0.0;
}
diff --git a/src/core/price/currency_converter.hpp b/src/core/price/currency_converter.hpp
index 5bdd44b..a2d8d82 100644
--- a/src/core/price/currency_converter.hpp
+++ b/src/core/price/currency_converter.hpp
@@ -24,7 +24,7 @@ namespace neroshop {
class Converter {
public:
// weight (mass)
- double to_kg(double amount, const std::string& unit_name) const;
+ static double to_kg(double amount, const std::string& unit_name);
static double lb_to_kg(double lb); //static double pound_to_kilogram(double pound); // The correct way of abbreviation in expressing singular or plural pounds is “lb.” though “lbs.”, which stands for libra, is the common abbreviation used in expressing pounds
static std::unique_ptr make_price_source(PriceSource source);
diff --git a/src/core/protocol/p2p/node.cpp b/src/core/protocol/p2p/node.cpp
index 63c39a8..7dbb1fc 100644
--- a/src/core/protocol/p2p/node.cpp
+++ b/src/core/protocol/p2p/node.cpp
@@ -999,7 +999,7 @@ bool neroshop::Node::validate(const std::string& key, const std::string& value)
assert(json["expiration_date"].is_string());
std::string expiration_date = json["expiration_date"].get();
if(neroshop_timestamp::is_expired(expiration_date)) {
- std::cerr << "Data has expired (exp date: " << expiration_date << " UTC)\n";
+ std::cerr << "Data has expired (exp date: " << expiration_date << ")\n";
// Notify the other nodes that this data has expired (so that once they receive a put with the expired data, it will be removed from their local hash table as soon as it goes through the validate function)
////send_put(key, value); // this should propagate the expiration information to other nodes in the DHT until the expired data is removed once and for all. Hmmm this could cause an endless loop ...
// This won't work unless all data contain a mandatory expiration date set on creation. A consensus mechanism may be necessary
diff --git a/src/gui/backend.cpp b/src/gui/backend.cpp
index 692da08..26d1624 100644
--- a/src/gui/backend.cpp
+++ b/src/gui/backend.cpp
@@ -86,6 +86,15 @@ QImage neroshop::Backend::base64ToImage(const QString& base64Data) {
}
//----------------------------------------------------------------
//----------------------------------------------------------------
+double neroshop::Backend::weightToKg(double amount, const QString& unit_name) const {
+ return neroshop::Converter::to_kg(amount, unit_name.toStdString());
+}
+
+double neroshop::Backend::lgToKg(double amount) const {
+ return neroshop::Converter::lb_to_kg(amount);
+}
+//----------------------------------------------------------------
+//----------------------------------------------------------------
QStringList neroshop::Backend::getCurrencyList() const
{
QStringList currency_list;
diff --git a/src/gui/backend.hpp b/src/gui/backend.hpp
index 657c2d7..aafc56d 100644
--- a/src/gui/backend.hpp
+++ b/src/gui/backend.hpp
@@ -28,6 +28,9 @@ public:
QString imageToBase64(const QImage& image); // un-tested
QImage base64ToImage(const QString& base64Data); // un-tested
+
+ Q_INVOKABLE double weightToKg(double amount, const QString& unit_name) const;
+ Q_INVOKABLE double lgToKg(double amount) const;
Q_INVOKABLE QStringList getCurrencyList() const;
Q_INVOKABLE int getCurrencyDecimals(const QString& currency) const;