mirror of https://github.com/layters/testshop
parent
be4fee03ce
commit
4ecc44ab85
@ -0,0 +1,146 @@
|
||||
// this page will display all products that have been searched for by the user in the search field
|
||||
import QtQuick 2.12//2.7 //(QtQuick 2.7 is lowest version for Qt 5.7)
|
||||
import QtQuick.Controls 2.12 // StackView
|
||||
import QtQuick.Layouts 1.12 // GridLayout
|
||||
import QtQuick.Shapes 1.3 // (since Qt 5.10) // Shape
|
||||
import QtGraphicalEffects 1.12//Qt5Compat.GraphicalEffects 1.15//= Qt6// ColorOverlay
|
||||
|
||||
// todo: place grid in stackview or swipeview for multiple grid pages (pagination mode)
|
||||
// todo: place grid in scrollview (infinite scroll mode) but in a separate file called CatalogGridViewInfiniteScroll.qml or CatalogGridViewLimitlessScroll.qml
|
||||
// todo: move this code to CatalogGridView.qml and create a CatalogListView
|
||||
// stackview functions
|
||||
////function next_page() {}
|
||||
////function prev_page() {}
|
||||
// Pagination mode
|
||||
/*StackView {
|
||||
id: catalog_pages
|
||||
anchors.fill: parent*/
|
||||
//index: 1//currentIndex: 1
|
||||
// Repeater inside StackView?
|
||||
// Infinite scroll mode
|
||||
/*Flickable {
|
||||
anchors.fill: parent
|
||||
contentHeight: catalog_grid.height
|
||||
contentWidth: catalog_grid.width*/
|
||||
// catalog view (Grid)
|
||||
Grid {
|
||||
id: catalog_grid
|
||||
rows: 2
|
||||
columns: 3
|
||||
spacing: 5//rowSpacing: 5; columnSpacing: 5
|
||||
anchors.centerIn: parent // place at center of parent
|
||||
//flow: Grid.TopToBottom
|
||||
function get_box(index) { // or get_item(index)?
|
||||
return catalog_grid_repeater.itemAt(index);
|
||||
}
|
||||
function get_box_count() {
|
||||
return catalog_grid_repeater.count; // count is really just the number of items in the model :O
|
||||
}
|
||||
|
||||
Repeater { // owns all items it instantiates
|
||||
id: catalog_grid_repeater
|
||||
model: (rows * columns)//fruitModel // rows and columns already set so this is useless (I think)
|
||||
// product box (GridBox)
|
||||
delegate: Rectangle { // delegates have a readonly "index" property that indicates the index of the delegate within the repeater
|
||||
id: product_box
|
||||
visible: true
|
||||
width: 220
|
||||
height: 220
|
||||
color: "#a0a0a0"// #a0a0a0 = 160,160,160
|
||||
//border.color: "white"
|
||||
//border.width: 1
|
||||
radius: 5
|
||||
|
||||
Image {
|
||||
id: verified_purchase_icon
|
||||
source: neroshopResourceDir + "/paid.png"
|
||||
visible: true//false // only show this icon if item has been purchased previously
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 10
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 10
|
||||
|
||||
height: 24; width: 24 // has no effect since image is scaled
|
||||
fillMode:Image.PreserveAspectFit; // the image is scaled uniformly to fit button without cropping
|
||||
|
||||
MouseArea {
|
||||
id: verified_purchase_icon_mouse_area
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
//acceptedButtons: Qt.LeftButton // for heart_icon ONLY
|
||||
onEntered: {
|
||||
console.log("Mouse is over paid icon")
|
||||
// show tooltip - todo: show tooltip while mouse is hovered over
|
||||
////if(has_purchased) {
|
||||
console.log("Icon pos (" + catalog_grid_repeater.itemAt(index).children[0].x + ", " + catalog_grid_repeater.itemAt(index).children[0].y + ")")
|
||||
console.log("Hint pos (" + hint.x + ", " + hint.y + ")")
|
||||
console.log("Grid pos (" + catalog_grid.x + ", " + catalog_grid.y + ")")
|
||||
console.log("Grid Parent pos (" + parent.x + ", " + parent.y + ")")
|
||||
//hint.x = catalog_grid_repeater.itemAt(index).children[0].x//hint.anchors.left = catalog_grid_repeater.itemAt(index).left//catalog_grid_repeater.itemAt(0).horizontalCenter//.left//parent.x + ((parent.width - this.width) / 2)
|
||||
//hint.y = catalog_grid_repeater.itemAt(index).children[0].y
|
||||
hint.x = catalog_grid.x// + catalog_grid_repeater.itemAt(index).children[0].x + catalog_grid_repeater.itemAt(index).children[0].width
|
||||
hint.y = catalog_grid.y//catalog_grid_repeater.itemAt(index).children[0].x
|
||||
/*NeroshopComponents.Hint*/hint.show("You've previously purchased this item", -1)//(!is_favorited) ? "Add to favorites" : "Remove from favorites"
|
||||
////}
|
||||
}
|
||||
onExited: {
|
||||
hint.hide()
|
||||
}
|
||||
//onClicked: { // for heart_icon ColorOverlay ONLY
|
||||
//if(!is_favorited) heart_icon.color = "#808080"
|
||||
//else heart_icon.color = "#e05d5d"
|
||||
//}
|
||||
}
|
||||
}
|
||||
ColorOverlay {
|
||||
anchors.fill: verified_purchase_icon
|
||||
source: verified_purchase_icon
|
||||
color:"#808080"//#808080 = 128, 128, 128//#1e509b = active color //(has_purchased) ? color: "#1e509b" : "#808080"
|
||||
visible: verified_purchase_icon.visible
|
||||
}
|
||||
|
||||
Image {
|
||||
id: heart_icon
|
||||
source: neroshopResourceDir + "/heart.png"
|
||||
visible: true
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 10
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 10
|
||||
|
||||
height: 24; width: 24 // has no effect since image is scaled
|
||||
fillMode:Image.PreserveAspectFit; // the image is scaled uniformly to fit button without cropping
|
||||
}
|
||||
ColorOverlay {
|
||||
anchors.fill: heart_icon
|
||||
source: heart_icon
|
||||
color:"#808080"//#808080 = 128, 128, 128//#e05d5d = active color //(is_favorited) ? color: "#e05d5d" : "#808080"
|
||||
visible: heart_icon.visible
|
||||
}
|
||||
|
||||
Image {
|
||||
id: product_image
|
||||
source: neroshopResourceDir + "/image_gallery.png"
|
||||
anchors.centerIn: parent
|
||||
|
||||
width: 128
|
||||
height: 128
|
||||
fillMode:Image.Stretch
|
||||
}
|
||||
/*ColorOverlay {
|
||||
anchors.fill: product_image
|
||||
source: product_image
|
||||
color:"#808080"//#808080 = 128, 128, 128
|
||||
}*/
|
||||
|
||||
Label {
|
||||
id: product_name_label
|
||||
text: ""//name
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 10
|
||||
anchors.top: product_image.bottom
|
||||
anchors.topMargin: 10
|
||||
}
|
||||
} // Catalog View Box (grid box)
|
||||
} // Repeater
|
||||
} // Catalog View (grid)
|
@ -0,0 +1,43 @@
|
||||
// custom Tooltip with arrow
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
import "." as NeroshopComponents // Triangle (in Triangle.qml)
|
||||
|
||||
ToolTip {
|
||||
id: hint
|
||||
text: ""//"position: " + tooltip_arrow.position + " (" + tooltip_arrow.offsetX + ")"//qsTr("A descriptive tool tip of what the button does")
|
||||
visible: false//true//false
|
||||
width: contentWidth + 20; height: 50 //width: (text.length * 10) + 20// assuming each character is 10 pixels in width
|
||||
//x: parent.x + ((parent.width - this.width) / 2) //anchors.left: parent.left; anchors.leftMargin: (parent.width - this.width) / 2
|
||||
//y: (parent.y + parent.height) + 5 //anchors.top: parent.bottom; anchors.topMargin: 5
|
||||
delay: 500 // shows tooltip after hovering over it for 0.5 seconds
|
||||
property string direction: "up"//"down"
|
||||
|
||||
contentItem: Text {
|
||||
text: hint.text
|
||||
font: hint.font
|
||||
color: "#ffffff"
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
|
||||
background: Rectangle {
|
||||
color: "#000000"// #0a0a0a = 10, 10, 10
|
||||
opacity: 0.9
|
||||
border.color: "#ffffff"
|
||||
border.width: 0
|
||||
radius: 5//10
|
||||
//gradient: "NightFade"
|
||||
NeroshopComponents.Triangle {
|
||||
//anchors.left: hint.left//hint.horizontalCenter
|
||||
//anchors.leftMargin: 100
|
||||
//anchors.top: parent.top//hint.top
|
||||
//anchors. :
|
||||
id: pointer
|
||||
//x: this.x
|
||||
//y: this.y
|
||||
////direction: hint.direction
|
||||
color: "black"
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,122 @@
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
import QtQuick.Layouts 1.12
|
||||
|
||||
import "." as NeroshopComponents // Hint
|
||||
|
||||
RowLayout {
|
||||
id: buttons_menu
|
||||
anchors.left: parent.right
|
||||
anchors.leftMargin: (-this.width - 20)
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 20
|
||||
|
||||
Button {
|
||||
text: qsTr("Seller Hub")
|
||||
//onClicked: _stackview.currentIndex = 0
|
||||
display: AbstractButton.IconOnly//AbstractButton.TextBesideIcon
|
||||
|
||||
icon.source: neroshopResourceDir + "/shop.png"
|
||||
icon.color: "#ffffff"
|
||||
|
||||
background: Rectangle {
|
||||
color: "royalblue"//"#808080"
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
text: qsTr("Messages")// todo: replace with message_count
|
||||
//onClicked: _stackview.currentIndex = 0
|
||||
display: AbstractButton.IconOnly//AbstractButton.TextBesideIcon
|
||||
|
||||
icon.source: neroshopResourceDir + "/mail.png"
|
||||
icon.color: "#ffffff"
|
||||
|
||||
background: Rectangle {
|
||||
color: "#524656"
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
id: order_button
|
||||
text: qsTr("Orders")
|
||||
//onClicked: _stackview.currentIndex = 0
|
||||
display: AbstractButton.IconOnly//AbstractButton.TextBesideIcon
|
||||
|
||||
icon.source: neroshopResourceDir + "/order.png"
|
||||
icon.color: "#ffffff"
|
||||
|
||||
background: Rectangle {
|
||||
color: "#607848"
|
||||
}
|
||||
|
||||
NeroshopComponents.Hint {
|
||||
id: order_button_hint
|
||||
text: "Orders"
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
id: account_button
|
||||
text: qsTr("User")//"Account Settings"
|
||||
//onClicked: _stackview.currentIndex = 0
|
||||
display: AbstractButton.IconOnly//AbstractButton.TextBesideIcon
|
||||
//flat: true
|
||||
//highlighted: true
|
||||
|
||||
icon.source: neroshopResourceDir + "/user.png"
|
||||
icon.color: "#ffffff"
|
||||
|
||||
background: Rectangle {
|
||||
color: "#cd8500"
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
id: cart_button
|
||||
// ref: https://doc.qt.io/qt-5/qml-qtquick-layouts-layout.html
|
||||
// fix alignment to StackLayout parent (no longer needed since we've set the preffered size, I think?)
|
||||
Layout.alignment: Qt.AlignTop
|
||||
// tell the layout that this child will have unique dimensions from the other children
|
||||
Layout.preferredHeight : 40
|
||||
Layout.preferredWidth : 100
|
||||
|
||||
background: Rectangle {
|
||||
//width: cart_button.width; height: cart_button.height//width: 100; height: 40
|
||||
color: "#323232"
|
||||
}
|
||||
|
||||
Text {
|
||||
id: cart_button_text
|
||||
text: "0"
|
||||
color: "#ffffff"
|
||||
font.bold: true
|
||||
anchors.left: cart_button.background.left
|
||||
anchors.leftMargin: 20
|
||||
anchors.top: cart_button.background.top
|
||||
anchors.topMargin: (cart_button.background.height - this.height) / 2
|
||||
}
|
||||
|
||||
Image {
|
||||
source: neroshopResourceDir + "/cart.png"
|
||||
height: 24; width: 24
|
||||
anchors.left: cart_button_text.right
|
||||
anchors.leftMargin: 10
|
||||
anchors.top: cart_button.background.top
|
||||
anchors.topMargin: (cart_button.background.height - this.height) / 2
|
||||
}
|
||||
}
|
||||
|
||||
/*Button {
|
||||
text: qsTr("")
|
||||
//onClicked: _stackview.currentIndex = 0
|
||||
display: AbstractButton.IconOnly//AbstractButton.TextBesideIcon
|
||||
|
||||
icon.source: neroshopResourceDir + "/image.png"
|
||||
icon.color: "#ffffff"
|
||||
|
||||
background: Rectangle {
|
||||
color: "#808080"
|
||||
}
|
||||
}*/
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
//import QtQuick.Layouts 1.12
|
||||
|
||||
import "." as NeroshopComponents
|
||||
|
||||
Item {
|
||||
TextField {
|
||||
id: search_bar
|
||||
color: "#ffffff" // textColor
|
||||
width: 400; height: 40
|
||||
selectByMouse: true
|
||||
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 20
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 20
|
||||
|
||||
background: Rectangle {
|
||||
color: "#050506"
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
id: search_button
|
||||
text: qsTr("Search")
|
||||
//onClicked:
|
||||
display: AbstractButton.IconOnly//AbstractButton.TextBesideIcon
|
||||
anchors.left: search_bar.right
|
||||
anchors.leftMargin: 1
|
||||
anchors.top: search_bar.top
|
||||
width: 50; height: search_bar.height
|
||||
|
||||
icon.source: neroshopResourceDir + "/search.png"
|
||||
icon.color: "#ffffff"
|
||||
|
||||
background: Rectangle {
|
||||
color: "#40404f"
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
pragma Singleton
|
||||
|
||||
import QtQuick 2.12 //import QtQml
|
||||
|
||||
QtObject {
|
||||
//objectName: "Style"
|
||||
//id: attributes
|
||||
//property string name
|
||||
//property int size
|
||||
//property variant attributes
|
||||
//FontLoader { id: fixedFont; name: "Courier" }
|
||||
//FontLoader { id: webFont; source: "http://www.mysite.com/myfont.ttf" }
|
||||
// General settings
|
||||
property bool darkTheme: true // or lightTheme
|
||||
// Catalog settings
|
||||
property bool gridView: true // or listView
|
||||
//property bool infiniteScroll: false // or loadMorePagination or numberPagination or prevNextPagination // infinite scroll will require a scrollview
|
||||
// Colors
|
||||
property string disabledColor: "#808080"
|
||||
|
||||
property string moneroGrayColor: "#4c4c4c"
|
||||
property string moneroOrangeColor: "#ff6600" // not sure if correct color
|
||||
|
||||
}
|
@ -0,0 +1,128 @@
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
import QtQuick.Shapes 1.3 // (since Qt 5.10) // Shape
|
||||
import QtGraphicalEffects 1.12//Qt5Compat.GraphicalEffects 1.15//= Qt6// ColorOverlay
|
||||
|
||||
Item {
|
||||
property string direction: "up"//"down"
|
||||
property string color: "white"
|
||||
readonly property int parentWidth: parent.width // get the Hint (Tooltip)'s width
|
||||
readonly property int parentHeight: parent.height // get the Hint (Tooltip)'s height
|
||||
readonly property int parentX: parent.x
|
||||
readonly property int parentY: parent.y
|
||||
|
||||
Image {
|
||||
id: triangle
|
||||
source: neroshopResourceDir + "/triangle.png"
|
||||
// direction: up
|
||||
x: parent.parentX + (parent.parentWidth - this.width) / 2
|
||||
y: parent.parentY - this.height// + 4
|
||||
//transform: Rotation { origin.x: triangle.x; origin.y: triangle.y; axis { x: 0; y: 0; z: 1 } angle: 180 }
|
||||
height: 24; width: 24
|
||||
}
|
||||
ColorOverlay {
|
||||
anchors.fill: triangle
|
||||
source: triangle
|
||||
color: parent.color
|
||||
visible: triangle.visible
|
||||
}
|
||||
}
|
||||
/*Shape {
|
||||
id: triangle
|
||||
property string direction: "down" // todo: add this property to custom Tooltip instead
|
||||
property string color: "#ffffff" // default color is set to white
|
||||
property string borderColor: "black"
|
||||
////property string borderWidth: 1
|
||||
|
||||
function get_offsetX() {
|
||||
if(direction == "up") return -20;
|
||||
if(direction == "down") return 20;
|
||||
if(direction == "left") return 3;
|
||||
if(direction == "right") return 4;
|
||||
return 20; // "down" value (default)
|
||||
}
|
||||
|
||||
function get_offsetY() {
|
||||
if(direction == "up") return -30;
|
||||
if(direction == "down") return 30;
|
||||
if(direction == "left") return 3;
|
||||
if(direction == "right") return 4;
|
||||
return 30; // "down" value (default)
|
||||
}
|
||||
readonly property real offsetX: get_offsetX()
|
||||
readonly property real offsetY: get_offsetY()
|
||||
|
||||
ShapePath {
|
||||
//capStyle: ShapePath.FlatCap//ShapePath.RoundCap
|
||||
strokeStyle: ShapePath.SolidLine
|
||||
strokeWidth: 1;
|
||||
strokeColor: triangle.borderColor
|
||||
fillColor: triangle.color
|
||||
PathLine { x: -triangle.offsetX ; y: -triangle.offsetY }
|
||||
PathLine { x: triangle.offsetX; y: -triangle.offsetY }
|
||||
PathLine { x: 0; y: 0 }
|
||||
}
|
||||
}*/
|
||||
/*
|
||||
// source: https://github.com/clogwog/qml-triangle/blob/master/Triangle.qml
|
||||
import QtQuick 2.4
|
||||
|
||||
// Cnavas is said to be slow so Shape is recommended over it
|
||||
Canvas {
|
||||
id: triangle
|
||||
antialiasing: true
|
||||
|
||||
property int triangleWidth: 60
|
||||
property int triangleHeight: 60
|
||||
property color strokeStyle: "#ffffff"
|
||||
property color fillStyle: "#ffffff"
|
||||
property int lineWidth: 3
|
||||
property bool fill: false
|
||||
property bool stroke: true
|
||||
property real alpha: 1.0
|
||||
states: [
|
||||
State {
|
||||
name: "pressed"; when: ma1.pressed
|
||||
PropertyChanges { target: triangle; fill: true; }
|
||||
}
|
||||
]
|
||||
|
||||
onLineWidthChanged:requestPaint();
|
||||
onFillChanged:requestPaint();
|
||||
onStrokeChanged:requestPaint();
|
||||
|
||||
signal clicked()
|
||||
|
||||
onPaint: {
|
||||
var ctx = getContext("2d");
|
||||
ctx.save();
|
||||
ctx.clearRect(0,0,triangle.width, triangle.height);
|
||||
ctx.strokeStyle = triangle.strokeStyle;
|
||||
ctx.lineWidth = triangle.lineWidth
|
||||
ctx.fillStyle = triangle.fillStyle
|
||||
ctx.globalAlpha = triangle.alpha
|
||||
ctx.lineJoin = "round";
|
||||
ctx.beginPath();
|
||||
|
||||
// put rectangle in the middle
|
||||
ctx.translate( (0.5 *width - 0.5*triangleWidth), (0.5 * height - 0.5 * triangleHeight))
|
||||
|
||||
// draw the rectangle
|
||||
ctx.moveTo(0,triangleHeight/2 ); // left point of triangle
|
||||
ctx.lineTo(triangleWidth, 0);
|
||||
ctx.lineTo(triangleWidth,triangleHeight);
|
||||
|
||||
ctx.closePath();
|
||||
if (triangle.fill)
|
||||
ctx.fill();
|
||||
if (triangle.stroke)
|
||||
ctx.stroke();
|
||||
ctx.restore();
|
||||
}
|
||||
MouseArea{
|
||||
id: ma1
|
||||
anchors.fill: parent
|
||||
onClicked: parent.clicked()
|
||||
}
|
||||
}
|
||||
*/
|
@ -0,0 +1 @@
|
||||
singleton Style 1.0 Style.qml
|
@ -0,0 +1,267 @@
|
||||
// this page will display all products that have been searched for by the user in the search field
|
||||
import QtQuick 2.12//2.7 //(QtQuick 2.7 is lowest version for Qt 5.7)
|
||||
import QtQuick.Controls 2.12 // StackView
|
||||
import QtQuick.Layouts 1.12 // GridLayout
|
||||
import QtQuick.Shapes 1.3 // (since Qt 5.10) // Shape
|
||||
import QtGraphicalEffects 1.12//Qt5Compat.GraphicalEffects 1.15//= Qt6// ColorOverlay
|
||||
|
||||
import "../components" as NeroshopComponents
|
||||
|
||||
Page {
|
||||
id: catalog_page
|
||||
background: Rectangle {
|
||||
//visible: true
|
||||
color:"transparent" // fixes white edges on borders when grid box radius is set
|
||||
}
|
||||
// test button
|
||||
Button {
|
||||
id: test_button
|
||||
text: "Test"
|
||||
onClicked: {
|
||||
/*if(catalog_view.rows == (3 * catalog_pages.index)) {
|
||||
console.log("3 rows reached. Move to next page");
|
||||
return;
|
||||
}*/
|
||||
// push 3 new items
|
||||
// repeater will insert the items since its model is fruitModel
|
||||
//fruitModel.insert(0, {"cost": 5.95, "name":"Pizza"})
|
||||
//fruitModel.insert(0, {"cost": 7.99, "name":"Cake"})
|
||||
//fruitModel.insert(0, {"cost": 2.15, "name":"Soda"})
|
||||
//fruitModel.insert(2, {"cost": 2.88, "name":"Chips"})
|
||||
console.log("number of models in fruitModel: " + fruitModel.count)
|
||||
//catalog_grid_repeater.itemAt(0).name = "DUDE"
|
||||
// This works
|
||||
console.log("Grid Boxes count: " + catalog.get_box_count())
|
||||
var box = catalog.get_box(3)//catalog_grid_repeater.itemAt(2)
|
||||
box.color = "blue"
|
||||
console.log( catalog.get_box(3).children[0] ) // Image (verified purchase icon)
|
||||
console.log( catalog.get_box(3).children[1] ) // ColorOverlay
|
||||
console.log( catalog.get_box(3).children[2] ) // Image (heart icon)
|
||||
console.log( catalog.get_box(3).children[3] ) // ColorOverlay
|
||||
console.log( catalog.get_box(3).children[4] ) // Image (product image)
|
||||
console.log( catalog.get_box(3).children[5] ) // Label (product name)
|
||||
console.log( catalog.get_box(3).children[6] ) // Label (product cost)
|
||||
//console.log( catalog.get_box(3).children[7] ) // ? (product stars)
|
||||
var box_index = 1
|
||||
var box_item = catalog.get_box(box_index);
|
||||
console.log("Catalog position: " + catalog.x + ", " + catalog.y )
|
||||
console.log("Box position: " + box_item.x + ", " + box_item.y )
|
||||
console.log("Box image(verified_icon) position: " + box_item.children[0].x + ", " + box_item.children[0].y )
|
||||
|
||||
console.log("Hint width: " + hint.width)
|
||||
console.log("Catalog Page Pos: " + catalog_page.x + ", " + catalog_page.y )
|
||||
console.log("Catalog Page Size " + catalog_page.width + ", " + catalog_page.height )
|
||||
// push page to catalog_page_stack
|
||||
catalog_page_stack.push(NeroshopComponents.CatalogGrid, {})//, {"color": "red"})
|
||||
|
||||
}
|
||||
x:-500
|
||||
background: Rectangle {
|
||||
color: "#6b5b95" // #ff6600 is the monero orange color
|
||||
radius: 0
|
||||
}
|
||||
}
|
||||
// shapes
|
||||
/*Shape {
|
||||
width: 200
|
||||
height: 150
|
||||
anchors.centerIn: parent
|
||||
ShapePath {
|
||||
strokeWidth: 4
|
||||
strokeColor: "red"
|
||||
strokeStyle: ShapePath.DashLine
|
||||
dashPattern: [ 1, 4 ]
|
||||
startX: 20; startY: 20
|
||||
PathLine { x: 180; y: 130 }
|
||||
PathLine { x: 20; y: 130 }
|
||||
PathLine { x: 20; y: 20 }
|
||||
}
|
||||
}
|
||||
*/
|
||||
// list model
|
||||
ListModel { // import QtQml.Models 2.15
|
||||
id: fruitModel
|
||||
|
||||
ListElement {
|
||||
name: "Apple"
|
||||
cost: 2.45
|
||||
attributes: [
|
||||
ListElement { description: "Core" },
|
||||
ListElement { description: "Deciduous" }
|
||||
]
|
||||
}
|
||||
ListElement {
|
||||
name: "Orange"
|
||||
cost: 3.25
|
||||
attributes: [
|
||||
ListElement { description: "Citrus" }
|
||||
]
|
||||
}
|
||||
ListElement {
|
||||
name: "Banana"
|
||||
cost: 1.95
|
||||
attributes: [
|
||||
ListElement { description: "Tropical" },
|
||||
ListElement { description: "Seedless" }
|
||||
]
|
||||
}
|
||||
/*ListElement {
|
||||
name: "Watermelon"
|
||||
cost: 3.95
|
||||
attributes: [
|
||||
ListElement { description: "Tropical" },
|
||||
ListElement { description: "Natural/Organic" }
|
||||
]
|
||||
}*/
|
||||
}
|
||||
|
||||
NeroshopComponents.Hint {
|
||||
id: hint
|
||||
}
|
||||
// navigational buttons
|
||||
/*RowLayout {
|
||||
}*/
|
||||
// todo: place grid in stackview or swipeview for multiple grid pages (pagination mode)
|
||||
// todo: place grid in scrollview (infinite scroll mode) but in a separate file called CatalogGridViewInfiniteScroll.qml
|
||||
// todo: move this code to CatalogGridView.qml
|
||||
// todo: create a CatalogListView
|
||||
// stackview functions
|
||||
////function next_page() {}
|
||||
////function prev_page() {}
|
||||
// Pagination mode
|
||||
StackView {
|
||||
id: catalog_page_stack
|
||||
anchors.fill: parent
|
||||
//index: 1//currentIndex: 1
|
||||
// Repeater inside StackView?
|
||||
// Infinite scroll mode
|
||||
/*Flickable {
|
||||
anchors.fill: parent
|
||||
contentHeight: catalog_view.height
|
||||
contentWidth: catalog_view.width*/
|
||||
// catalog view (Grid)
|
||||
/*Grid {
|
||||
id: catalog_view
|
||||
rows: 2//40//2
|
||||
columns: 3
|
||||
spacing: 5//rowSpacing: 5; columnSpacing: 5
|
||||
anchors.centerIn: parent // place at center of parent
|
||||
//flow: Grid.TopToBottom
|
||||
|
||||
Repeater { // owns all items it instantiates
|
||||
id: catalog_grid_repeater
|
||||
model: fruitModel//10 // rows and columns already set so this is useless
|
||||
//delegate: this { id: _id }
|
||||
// product box (GridBox)
|
||||
Rectangle {
|
||||
id: product_box
|
||||
visible: true
|
||||
width: 220
|
||||
height: 220
|
||||
color: "#a0a0a0"// #a0a0a0 = 160,160,160
|
||||
//border.color: "white"
|
||||
//border.width: 1
|
||||
radius: 5
|
||||
|
||||
Image {
|
||||
id: verified_purchase_icon
|
||||
source: neroshopResourceDir + "/paid.png"
|
||||
visible: true//false // only show this icon if item has been purchased previously
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 10
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 10
|
||||
|
||||
height: 24; width: 24 // has no effect since image is scaled
|
||||
fillMode:Image.PreserveAspectFit; // the image is scaled uniformly to fit button without cropping
|
||||
|
||||
MouseArea {
|
||||
id: verified_purchase_icon_mouse_area
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
//acceptedButtons: Qt.LeftButton // for heart_icon ONLY
|
||||
onEntered: {
|
||||
console.log("Mouse is over paid icon")
|
||||
// show tooltip - todo: show tooltip while mouse is hovered over
|
||||
////if(has_purchased) {
|
||||
//hint.anchors.left = catalog_grid_repeater.itemAt(0).left//catalog_grid_repeater.itemAt(0).horizontalCenter//.left//parent.x + ((parent.width - this.width) / 2)
|
||||
hint.show("You've previously purchased this item", -1)//(!is_favorited) ? "Add to favorites" : "Remove from favorites"
|
||||
////}
|
||||
}
|
||||
onExited: {
|
||||
hint.hide()
|
||||
}
|
||||
//onClicked: { // for heart_icon ColorOverlay ONLY
|
||||
//if(!is_favorited) heart_icon.color = "#808080"
|
||||
//else heart_icon.color = "#e05d5d"
|
||||
//}
|
||||
}
|
||||
}
|
||||
ColorOverlay {
|
||||
anchors.fill: verified_purchase_icon
|
||||
source: verified_purchase_icon
|
||||
color:"#808080"//#808080 = 128, 128, 128//#1e509b = active color //(has_purchased) ? color: "#1e509b" : "#808080"
|
||||
visible: verified_purchase_icon.visible
|
||||
}
|
||||
|
||||
Image {
|
||||
id: heart_icon
|
||||
source: neroshopResourceDir + "/heart.png"
|
||||
visible: true
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 10
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 10
|
||||
|
||||
height: 24; width: 24 // has no effect since image is scaled
|
||||
fillMode:Image.PreserveAspectFit; // the image is scaled uniformly to fit button without cropping
|
||||
}
|
||||
ColorOverlay {
|
||||
anchors.fill: heart_icon
|
||||
source: heart_icon
|
||||
color:"#808080"//#808080 = 128, 128, 128//#e05d5d = active color //(is_favorited) ? color: "#e05d5d" : "#808080"
|
||||
visible: heart_icon.visible
|
||||
}
|
||||
|
||||
Image {
|
||||
id: product_image
|
||||
source: neroshopResourceDir + "/image_gallery.png"
|
||||
anchors.centerIn: parent
|
||||
|
||||
width: 128
|
||||
height: 128
|
||||
fillMode:Image.Stretch
|
||||
}
|
||||
//ColorOverlay {
|
||||
// anchors.fill: product_image
|
||||
// source: product_image
|
||||
// color:"#808080"//#808080 = 128, 128, 128
|
||||
//}
|
||||
|
||||
Label {
|
||||
id: product_name_label
|
||||
text: ""//name
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 10
|
||||
anchors.top: product_image.bottom
|
||||
anchors.topMargin: 10
|
||||
}
|
||||
} // Catalog View Box (grid box)
|
||||
} // Repeater
|
||||
}*/ // Catalog View (grid)
|
||||
//}
|
||||
NeroshopComponents.CatalogGrid {
|
||||
id: catalog
|
||||
}
|
||||
|
||||
/*Button {
|
||||
text: "<"
|
||||
onClicked: catalog_page_stack.replace(page, StackView.PopTransition)
|
||||
}
|
||||
Button {
|
||||
text: ">"
|
||||
onClicked: catalog_page_stack.replace(page, StackView.PushTransition)
|
||||
}*/
|
||||
|
||||
} // StackView
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
// consists of the navigational bar with menus and search bar
|
||||
import QtQuick 2.12//2.7 //(QtQuick 2.7 is lowest version for Qt 5.7)
|
||||
import QtQuick.Controls 2.12 // StackView
|
||||
import QtQuick.Layouts 1.12 // GridLayout
|
||||
import QtQuick.Shapes 1.3 // (since Qt 5.10) // Shape
|
||||
import QtGraphicalEffects 1.12//Qt5Compat.GraphicalEffects 1.15//= Qt6// ColorOverlay
|
||||
|
||||
import "../components" as NeroshopComponents // Tooltip
|
||||
// number to string: my_number.toString()
|
||||
// string to number: Number(my_string)
|
||||
Page {
|
||||
id: home_page
|
||||
background: Rectangle {
|
||||
//visible: true
|
||||
color:"transparent" // fixes white edges on borders when grid box radius is set
|
||||
}
|
||||
}
|
@ -0,0 +1,525 @@
|
||||
// todo: rename this file to LoginPage.qml
|
||||
// requires Qt version 5.12 (latest is 5.15 as of this writing). See https://doc.qt.io/qt-5/qt5-intro.html
|
||||
import QtQuick 2.12//2.7 //(QtQuick 2.7 is lowest version for Qt 5.7)
|
||||
import QtQuick.Controls 2.12//2.0 // (requires at least Qt 5.12 where QtQuick.Controls 1 is deprecated. See https://doc.qt.io/qt-5/qtquickcontrols-index.html#versions) // needed for built-in styles // Page, TextField, TextArea (multi-lined TextField), TextFieldStyle//import QtQuick.Controls.Material 2.12 // Other styles:
|
||||
//import QtQuick.Controls.Material 2.0
|
||||
//import QtQuick.Controls.Styles 1.4 // ApplicationWindowStyle, TextFieldStyle
|
||||
import QtQuick.Layouts 1.12//1.15 // The module is new in Qt 5.1 and requires Qt Quick 2.1. // RowLayout, ColumnLayout, GridLayout, StackLayout, Layout
|
||||
import QtQuick.Dialogs 1.3 // MessageDialog (since Qt 5.2)
|
||||
import QtGraphicalEffects 1.12 // LinearGradient
|
||||
import Qt.labs.platform 1.1 // FileDialog (since Qt 5.8) // change to "import QtQuick.Dialogs" if using Qt 6.2
|
||||
|
||||
//import neroshop.Wallet 1.0
|
||||
import "../components" as NeroshopComponents
|
||||
|
||||
Page {
|
||||
id: main_page
|
||||
title: qsTr("Main Page")
|
||||
//Rectangle {
|
||||
// color:"red"
|
||||
//}
|
||||
///////////////////////////
|
||||
function copy_to_clipboard() { // copies seed (mnemonic)
|
||||
// If text edit string is empty, exit function
|
||||
if(!seed_display_edit.text) return;
|
||||
// Select all text from edit then copy the selected text
|
||||
seed_display_edit.selectAll()
|
||||
seed_display_edit.copy()
|
||||
console.log("Copied to clipboard");
|
||||
}
|
||||
///////////////////////////
|
||||
//Wallet {
|
||||
// id: wallet
|
||||
//}
|
||||
///////////////////////////
|
||||
function generate_keys() {
|
||||
// generate a unique wallet seed (mnemonic)
|
||||
let error = Wallet.create_random_wallet(wallet_password_create_edit.text, wallet_password_confirm_edit.text, neroshopWalletDir + "/auth")//"wallet")
|
||||
// if wallet passwords don't match, display error message
|
||||
let WALLET_PASSWORD_NO_MATCH = 2
|
||||
let WALLET_ALREADY_EXISTS = 3;
|
||||
if(error == WALLET_PASSWORD_NO_MATCH) {//if(wallet_password_confirm_edit.text != wallet_password_create_edit.text) {
|
||||
//important_message_field.x = wallet_password_confirm_edit.x
|
||||
important_message_field.text = qsTr("Wallet passwords do not match")
|
||||
important_message_field.visible = true
|
||||
/*message_box.text = qsTr("Wallet passwords do not match")
|
||||
message_box.open()*/
|
||||
}
|
||||
else if(error == WALLET_ALREADY_EXISTS) {
|
||||
important_message_field.text = qsTr("A wallet file with the same name already exists")
|
||||
important_message_field.visible = true
|
||||
}
|
||||
// then copy the mnemonic to the seed display edit
|
||||
seed_display_edit.text = Wallet.get_mnemonic()
|
||||
// show important message (only if wallet keys were successfully created)
|
||||
if(seed_display_edit.text) {
|
||||
//important_message_field.x = (genkey_page.width / 2) - (important_message_field.width / 2)// place at center of genkey_page//generate_key_button.x
|
||||
//important_message_field.y = generate_key_button.y + generate_key_button.height + 20
|
||||
important_message_field.text = qsTr("These words are the key to your account. Please store them safely!")
|
||||
important_message_field.visible = true
|
||||
// clear wallet password text fields
|
||||
wallet_password_create_edit.text = "";
|
||||
wallet_password_confirm_edit.text = "";
|
||||
}
|
||||
}
|
||||
///////////////////////////
|
||||
function register_wallet() {
|
||||
// if not key generated, then generate key
|
||||
if(!seed_display_edit.text) {
|
||||
message_box.text = qsTr("Please generate your keys before registering")
|
||||
message_box.open()
|
||||
return; // exit function and do not proceed any further
|
||||
}
|
||||
// do a regex check on the username before proceeding
|
||||
// make sure username is not taken (requires a database check)
|
||||
// register the wallet primary key to the database
|
||||
// switch (login) to home page
|
||||
//stack.push(home_page)
|
||||
page_loader.source = "home_page.qml"
|
||||
}
|
||||
///////////////////////////
|
||||
// consists of login and registration menus
|
||||
MessageDialog {
|
||||
id: message_box
|
||||
//visible: false
|
||||
title: "message"
|
||||
text: "It's so cool that you are using Qt Quick."
|
||||
//detailedText:
|
||||
//icon: StandardIcon.Question
|
||||
////standardButtons: StandardButton.Ok | StandardButton.Cancel
|
||||
//modal: true // blocks input to other content beneath the dialog.
|
||||
|
||||
//onAccepted: console.log("Ok clicked")
|
||||
//onRejected: console.log("Cancel clicked")
|
||||
}
|
||||
///////////////////////////
|
||||
FileDialog {
|
||||
id: wallet_file_dialog
|
||||
fileMode: FileDialog.OpenFile
|
||||
currentFile: wallet_upload_edit.text // currentFile is deprecated since Qt 6.3. Use selectedFile instead
|
||||
folder: neroshopWalletDir//StandardPaths.writableLocation(StandardPaths.HomeLocation) + "/neroshop"//StandardPaths.writableLocation(StandardPaths.AppDataLocation) // refer to https://doc.qt.io/qt-5/qstandardpaths.html#StandardLocation-enum
|
||||
nameFilters: ["Wallet files (*.keys)"]
|
||||
//options: FileDialog.ReadOnly // will not allow you to create folders while file dialog is opened
|
||||
}
|
||||
// gtk error: Failed to load image-missing.png on Linux (fix: ?)
|
||||
// See https://forums.wxwidgets.org/viewtopic.php?t=47187
|
||||
///////////////////////////
|
||||
StackLayout { // Perfect for a stack of items where only one item is visible at a time//ColumnLayout { // From top to bottom
|
||||
id: auth_stack // auth_menu inside home menu
|
||||
//anchors.fill: parent // will fill entire Window area
|
||||
currentIndex: 1
|
||||
width: 800//500
|
||||
height: 500//300
|
||||
x: parent.width / 2 - this.width / 2 // window is the id of ApplicationWindow
|
||||
y: parent.height / 2 - this.height / 2
|
||||
|
||||
// generate auth keys page
|
||||
Rectangle {
|
||||
id: genkey_page
|
||||
color: (NeroshopComponents.Style.darkTheme) ? "black" : "#a0a0a0"//160, 160, 160
|
||||
// optional pseudonym edit
|
||||
TextField {
|
||||
id: opt_username_edit
|
||||
placeholderText: qsTr("Pseudonym (optional)")
|
||||
placeholderTextColor: "#696969" // dim gray
|
||||
color:"#6b5b95"
|
||||
//x: seed_display_scrollview.x
|
||||
anchors.left: seed_display_scrollview.left
|
||||
//y: seed_display_scrollview.y + seed_display_scrollview.height + 30
|
||||
anchors.top: seed_display_scrollview.bottom
|
||||
anchors.topMargin: 30
|
||||
selectByMouse: true
|
||||
|
||||
width: 300
|
||||
background: Rectangle {
|
||||
color: (NeroshopComponents.Style.darkTheme) ? "transparent": "#101010"//"#101010" = rgb(16, 16, 16)
|
||||
border.color: "#696969" // dim gray//"#ffffff"
|
||||
border.width: (NeroshopComponents.Style.darkTheme) ? 1 : 0
|
||||
}
|
||||
//validator: RegExpValidator { regExp: /^(?=.{8,20}$)(?![_.])(?!.*[_.]{2})[a-zA-Z0-9._]+(?<![_.])$/ } // validator: RegularExpressionValidator { regularExpression: /[0-9A-F]+/ } // since Qt 5.14
|
||||
}
|
||||
// register button
|
||||
Button {
|
||||
id: wallet_register_button
|
||||
text: qsTr("Register")
|
||||
//x: copy_button.x//opt_username_edit.x + opt_username_edit.width + 50
|
||||
anchors.left: opt_username_edit.right//copy_button.left
|
||||
anchors.leftMargin: 20
|
||||
//y: opt_username_edit.y + verticalCenter of username_edit
|
||||
anchors.top: opt_username_edit.top
|
||||
anchors.topMargin: (opt_username_edit.height / 2) - (this.height / 2)
|
||||
width: 180//copy_button.width
|
||||
height: 60 + 5//50 // width will be set automatically based on text length
|
||||
onClicked: register_wallet()
|
||||
|
||||
contentItem: Text {
|
||||
font.bold: true
|
||||
text: wallet_register_button.text
|
||||
color: "#ffffff" // white
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
|
||||
background: Rectangle {
|
||||
color: "#6b5b95" // #ff6600 is the monero orange color
|
||||
radius: 0
|
||||
}
|
||||
}
|
||||
// change wallet path edit
|
||||
// ...
|
||||
// wallet password create edit
|
||||
TextField {
|
||||
id: wallet_password_create_edit
|
||||
placeholderText: qsTr("Wallet Password")
|
||||
placeholderTextColor: "#a9a9a9" // darkgray
|
||||
color: NeroshopComponents.Style.moneroOrangeColor//"#ff6600" // textColor
|
||||
echoMode: TextInput.Password//TextInput.PasswordEchoOnEdit
|
||||
selectByMouse: true
|
||||
//validator: RegularExpressionValidator { regularExpression: "^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-]).{8,}$" }
|
||||
//x: generate_key_button.x + generate_key_button.width + 15
|
||||
anchors.left: generate_key_button.right // generate_key_button.x + the width of generate_key_button
|
||||
anchors.leftMargin: 15
|
||||
//y: generate_key_button.y
|
||||
anchors.top: generate_key_button.top//generate_key_button.verticalCenter = will place text field at center of generate_key_button vertically (y)
|
||||
|
||||
width: 300//; height: generate_key_button.height / 2
|
||||
background: Rectangle {
|
||||
color: NeroshopComponents.Style.moneroGrayColor//#4c4c4c = monero gray color//"#404040" = 64, 64, 64
|
||||
border.color: parent.placeholderTextColor
|
||||
border.width: (NeroshopComponents.Style.darkTheme) ? 1 : 0
|
||||
}
|
||||
// todo: maybe add a regex validator
|
||||
}
|
||||
// wallet password confirm edit
|
||||
TextField {
|
||||
id: wallet_password_confirm_edit
|
||||
placeholderText: qsTr("Confirm Wallet Password")
|
||||
placeholderTextColor: "#a9a9a9" // darkgray
|
||||
color: NeroshopComponents.Style.moneroOrangeColor//"#ff6600" // textColor
|
||||
echoMode: TextInput.Password
|
||||
selectByMouse: true
|
||||
x: wallet_password_create_edit.x
|
||||
y: wallet_password_create_edit.y + wallet_password_create_edit.height + 5
|
||||
width: wallet_password_create_edit.width; height: wallet_password_create_edit.height
|
||||
background: Rectangle {
|
||||
color: NeroshopComponents.Style.moneroGrayColor
|
||||
border.color: parent.placeholderTextColor
|
||||
border.width: (NeroshopComponents.Style.darkTheme) ? 1 : 0
|
||||
}
|
||||
}
|
||||
// generate key button
|
||||
Button {
|
||||
id: generate_key_button
|
||||
text: qsTr("Generate Keys")
|
||||
x: 20
|
||||
y: 20
|
||||
width: 150
|
||||
height: 60 + 5//50 // width will be set automatically based on text length
|
||||
|
||||
onClicked: generate_keys()
|
||||
|
||||
contentItem: Text {
|
||||
font.bold: true
|
||||
text: generate_key_button.text
|
||||
color: "#ffffff" // white
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
|
||||
background: Rectangle {
|
||||
color: '#ff6600' // #ff6600 is the monero orange color
|
||||
radius: 0
|
||||
}
|
||||
}
|
||||
// Important message box
|
||||
TextField {
|
||||
id: important_message_field
|
||||
visible: false
|
||||
x: (genkey_page.width / 2) - (this.width / 2)// place at center of genkey_page//generate_key_button.x
|
||||
y: generate_key_button.y + generate_key_button.height + 20
|
||||
/*x: seed_display_scrollview.x
|
||||
y: seed_display_scrollview.y + seed_display_scrollview.height + 10*/
|
||||
readOnly: true
|
||||
//text: qsTr("")
|
||||
color: "#ffffff"// text color
|
||||
background: Rectangle {
|
||||
color: "firebrick"
|
||||
}
|
||||
}
|
||||
// wallet seed display
|
||||
ScrollView {
|
||||
id: seed_display_scrollview
|
||||
//anchors.fill: parent
|
||||
width: 500//300
|
||||
height: 250//150
|
||||
x: generate_key_button.x//20
|
||||
y: (important_message_field.visible) ? important_message_field.y + important_message_field.height + 20 : generate_key_button.y + generate_key_button.height + 20//genkey_page.height - this.height - 20
|
||||
|
||||
TextArea {
|
||||
id: seed_display_edit
|
||||
readOnly: true
|
||||
//text: qsTr("")
|
||||
color: "#000000" // text color
|
||||
//selectionColor: "transparent"
|
||||
// Style
|
||||
background: Rectangle {
|
||||
color: "#708090"
|
||||
border.color:"#ffffff" // white (since dark mode is default)//border.width: 1//radius: 2
|
||||
}
|
||||
// on Left mouse clicked
|
||||
MouseArea {
|
||||
id: seed_display_mouse_area
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||
//cursorShape: Qt.IBeamCursor
|
||||
onClicked: (mouse)=> {
|
||||
// left mouse = displayListOptions()
|
||||
if ((mouse.button == Qt.LeftButton)) {
|
||||
//console.log("Left mouse clicked on seed_display_edit");
|
||||
}
|
||||
// right mouse = selectAll()
|
||||
if ((mouse.button == Qt.RightButton)) {
|
||||
//console.log("Right mouse clicked on seed_display_edit");
|
||||
}
|
||||
}
|
||||
/*onEntered: {
|
||||
this.cursorShape = Qt.IBeamCursor
|
||||
}*/
|
||||
}
|
||||
// text options for copy, paste, etc. (experimental)
|
||||
/*ListView {
|
||||
anchors.fill: parent
|
||||
////model: ContactModel {}
|
||||
delegate: contactDelegate
|
||||
highlight: Rectangle { color: "lightsteelblue"; radius: 5 }
|
||||
focus: true
|
||||
x: seed_display_mouse_area.mouseX
|
||||
y: seed_display_mouse_area.mouseY
|
||||
}*/
|
||||
}
|
||||
}
|
||||
// copy_button (copies to the clipboard)
|
||||
Button {
|
||||
id: copy_button
|
||||
width: 100; height: seed_display_scrollview.height//50
|
||||
//x: (seed_display_scrollview.x + seed_display_scrollview.width) + (genkey_page.width / 2) - ((this.width + seed_display_scrollview.width + 10) / 2) //(seed_display_scrollview.x + seed_display_scrollview.width) + 5
|
||||
anchors.left: seed_display_scrollview.right//seed_display_scrollview.horizontalCenter
|
||||
anchors.leftMargin: (parent.width / 2) - ((this.width + seed_display_scrollview.width + 10) / 2)
|
||||
//y: seed_display_scrollview.y + (seed_display_scrollview.height / 2) - (this.height / 2)
|
||||
anchors.top: seed_display_scrollview.top
|
||||
anchors.topMargin: (seed_display_scrollview.height / 2) - (this.height / 2)
|
||||
text: qsTr("Copy") // rather have an icon with a tooltip than a text
|
||||
display: AbstractButton.IconOnly // will only show the icon and not the text
|
||||
// this only works on selected text
|
||||
onClicked: copy_to_clipboard()//seed_display_edit.copy()//copy_to_clipboard()
|
||||
|
||||
ToolTip.delay: 500 // shows tooltip after hovering for 0.5 second
|
||||
ToolTip.visible: hovered
|
||||
ToolTip.text: qsTr("Copy to clipboard")
|
||||
|
||||
icon.source: neroshopResourceDir + "/copy.png"
|
||||
icon.color: "#ffffff"
|
||||
//icon.height: 24; icon.width: 24
|
||||
|
||||
background: Rectangle {
|
||||
color: "#808080"
|
||||
radius: 0
|
||||
border.color: this.parent.hovered ? "#ffffff" : this.color
|
||||
}
|
||||
}
|
||||
} // eof genkey_page
|
||||
// walletfile auth page
|
||||
// Upload button with read-only textfield
|
||||
Rectangle {
|
||||
id: wallet_file_auth_page
|
||||
color: '#000000'//'#a0a0a0' // #a0a0a0 = 160,160,160
|
||||
//gradient: Gradient {
|
||||
// GradientStop { position: 0.0; color: "white" }
|
||||
// GradientStop { position: 1.0; color: "black" }
|
||||
//}
|
||||
//anchors.right: parent.right//implicitWidth: 200
|
||||
//implicitHeight: 200
|
||||
// add spacing from parent (padding - located inside the borders of an element)
|
||||
//anchors.margins: 50//anchors.leftPadding: 20
|
||||
// wallet_file name edit
|
||||
//ScrollView {
|
||||
// id: wallet_upload_scrollview
|
||||
TextField {
|
||||
id: wallet_upload_edit // for displaying wallet file name or path
|
||||
x: (wallet_file_auth_page.width - wallet_upload_button.width - this.width) / 2//20
|
||||
y: 20 // top_margin
|
||||
width: 300; height: 30
|
||||
readOnly: true
|
||||
text: wallet_file_dialog.file//property url source: wallet_file_dialog.file; text: this.source
|
||||
////placeholderText: qsTr("...") // eh ... probably not necessary (better to just leave it blank)
|
||||
// change TextField color
|
||||
background: Rectangle {
|
||||
color: "#708090"
|
||||
border.color:"#ffffff" // white (since dark mode is default)//border.width: 1//radius: 2
|
||||
}
|
||||
}
|
||||
//}
|
||||
// upload button
|
||||
Button {
|
||||
id: wallet_upload_button
|
||||
text: qsTr("Upload")
|
||||
onClicked: wallet_file_dialog.open()
|
||||
display: AbstractButton.IconOnly//AbstractButton.TextBesideIcon//AbstractButton.TextOnly
|
||||
//hoverEnabled: true
|
||||
x: wallet_upload_edit.x + wallet_upload_edit.width + 5
|
||||
y: wallet_upload_edit.y
|
||||
width: 50
|
||||
height: wallet_upload_edit.height
|
||||
|
||||
icon.source: neroshopResourceDir + "/upload.png"
|
||||
icon.color: "#ffffff"
|
||||
// can only have 1 contentItem at a time (a contentItem is not needed for Button)
|
||||
/*contentItem: Image {
|
||||
source: neroshopResourceDir + "/upload.png"
|
||||
height: 24; width: 24 // has no effect since image is scaled
|
||||
fillMode:Image.PreserveAspectFit; // the image is scaled uniformly to fit button without cropping // https://doc.qt.io/qt-6/qml-qtquick-image.html#fillMode-prop
|
||||
}
|
||||
contentItem: Text {
|
||||
text: wallet_upload_button.text
|
||||
color: "#ffffff"
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}*/
|
||||
|
||||
background: Rectangle {
|
||||
color: "#808080"/*parent.down ? "#bbbbbb" :
|
||||
(parent.hovered ? "#d6d6d6" : "#f6f6f6")*/
|
||||
radius: 0
|
||||
border.color: wallet_upload_button.hovered ? "#ffffff" : this.color//"#ffffff"//control.down ? "#17a81a" : "#21be2b"
|
||||
}
|
||||
|
||||
ToolTip.delay: 500 // shows tooltip after hovering for 0.5 second
|
||||
ToolTip.visible: hovered
|
||||
ToolTip.text: qsTr("Upload wallet file")
|
||||
}
|
||||
/*Label {
|
||||
id: wallet_file_password_label
|
||||
text: qsTr("Wallet file password")
|
||||
}*/
|
||||
// wallet password textfield
|
||||
TextField {//TextInput {
|
||||
id: wallet_password_edit
|
||||
x: wallet_upload_edit.x
|
||||
y: wallet_upload_edit.y + wallet_upload_edit.height + 10
|
||||
width: wallet_upload_edit.width//; height:
|
||||
placeholderText: qsTr("Wallet Password")
|
||||
placeholderTextColor: "#696969" // dim gray
|
||||
color: "#5f3dc4"//"#402ef7"//"orange" // textColor
|
||||
echoMode: TextInput.Password//TextInput.PasswordEchoOnEdit // hide sensative text
|
||||
selectByMouse: true // can select parts of or all of text with mouse
|
||||
// change TextField color (only works with TextFields not TextInputs)
|
||||
background: Rectangle {
|
||||
color: wallet_file_auth_page.color
|
||||
//opacity: 0.5
|
||||
border.color: "#696969" // dim gray//"#ffffff"
|
||||
}
|
||||
}
|
||||
// confirm button
|
||||
Button {
|
||||
id: wallet_file_confirm_button
|
||||
text: qsTr("Confirm")
|
||||
x: wallet_password_edit.x
|
||||
y: wallet_file_auth_page.height - this.height - 20//wallet_password_edit.y + wallet_password_edit.height + 0
|
||||
width: 150; height: 60
|
||||
//onClicked: Authenticator.auth_walletfile()
|
||||
|
||||
contentItem: Text {
|
||||
text: wallet_file_confirm_button.text
|
||||
color: "#ffffff"
|
||||
// place text at center of button
|
||||
horizontalAlignment: Text.AlignHCenter//anchors.centerIn: parent // no work :(
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
|
||||
background: Rectangle {
|
||||
color: '#6b5b95'//#5f3dc4 = (95, 61, 196)//add to cart button colors =>//"#6b5b95"//#6b5b95 = (107, 91, 149)//"#483d8b"//#483d8b = (72, 61, 139)//"#ff6600"//#ff6600 is the monero orange color
|
||||
radius: 0
|
||||
}
|
||||
}
|
||||
} // eof wallet_file_authentication_page
|
||||
Rectangle {
|
||||
id: seed_auth_page
|
||||
color: 'plum'
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: keys_auth_page
|
||||
color: 'blue'
|
||||
}
|
||||
/*Button {
|
||||
// control properties
|
||||
//padding: 10
|
||||
// abstractbutton properties
|
||||
text: "Ok"
|
||||
onClicked: model.submit()
|
||||
// button properties
|
||||
flat: false
|
||||
highlighted: false
|
||||
}*/
|
||||
}
|
||||
///////////////////////////
|
||||
RowLayout {//TabBar {
|
||||
//id: access_buttons_container
|
||||
x: auth_stack.x + (auth_stack.width / 2) - (this.width / 2) // center the x
|
||||
y: (auth_stack.y + auth_stack.height) + 5// 5 is the padding // lower the y
|
||||
|
||||
Button {//TabButton { // must be used in conjunction with a TabBar according to: https://doc.qt.io/qt-5/qml-qtquick-controls2-tabbutton.html
|
||||
text: qsTr("register (genkey)")
|
||||
onClicked: auth_stack.currentIndex = 0
|
||||
|
||||
background: Rectangle {
|
||||
color: "#00aebf"
|
||||
}
|
||||
}
|
||||
Button {//TabButton {
|
||||
id: login_button//auth_walletfile_button
|
||||
text: qsTr("auth_with_walletfile")
|
||||
onClicked: auth_stack.currentIndex = 1
|
||||
|
||||
contentItem: Text {
|
||||
font.family: "Consolas";
|
||||
font.pointSize: 10;
|
||||
font.bold: true
|
||||
|
||||
text: login_button.text
|
||||
color: "#ffffff" // white text
|
||||
}
|
||||
|
||||
background: Rectangle {
|
||||
color: NeroshopComponents.Style.moneroOrangeColor//"#ff6600"//parent.down ? "#bbbbbb" :
|
||||
//(parent.hovered ? "#d6d6d6" : "#f6f6f6")
|
||||
radius: 0
|
||||
border.color: login_button.hovered ? "#ffffff" : this.color//"#ffffff"//control.down ? "#17a81a" : "#21be2b"
|
||||
}
|
||||
}
|
||||
Button {//TabButton {
|
||||
text: qsTr("auth_with_seed")
|
||||
onClicked: auth_stack.currentIndex = 2
|
||||
|
||||
background: Rectangle {
|
||||
color: NeroshopComponents.Style.moneroGrayColor
|
||||
}
|
||||
}
|
||||
Button {//TabButton {
|
||||
text: qsTr("auth_with_keys")
|
||||
onClicked: auth_stack.currentIndex = 3
|
||||
|
||||
background: Rectangle {
|
||||
color: "#402ef7"
|
||||
}
|
||||
}
|
||||
Button {//TabButton {
|
||||
text: qsTr("auth_with_hw")
|
||||
//onClicked: auth_stack.currentIndex = 4
|
||||
|
||||
background: Rectangle {
|
||||
color: "red"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
// This is the order confirmation/checkout page that is displayed before an order is placed
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
import QtQuick.Layouts 1.12
|
||||
|
||||
import "../components" as NeroshopComponents
|
@ -0,0 +1,6 @@
|
||||
// This page displays the product page upon clicking on a product in the catalog view
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Controls 2.12
|
||||
import QtQuick.Layouts 1.12
|
||||
|
||||
import "../components" as NeroshopComponents
|
@ -0,0 +1,114 @@
|
||||
#include "config.hpp"
|
||||
|
||||
lua_State * neroshop::lua_state(luaL_newstate());
|
||||
|
||||
bool neroshop::load_config() {
|
||||
std::string user = neroshop::device::get_user();
|
||||
// "/home/<user>/.config/neroshop"
|
||||
#if defined(NEROSHOP_USE_QT)
|
||||
std::string neroshop_config_path = NEROSHOP_DEFAULT_CONFIGURATION_PATH.toStdString();
|
||||
#else
|
||||
std::string neroshop_config_path = NEROSHOP_DEFAULT_CONFIGURATION_PATH;
|
||||
#endif
|
||||
// "/home/<user>/.config/neroshop/settings.lua"
|
||||
std::string neroshop_config_name = neroshop_config_path + "/" + NEROSHOP_CONFIGURATION_FILE;
|
||||
Script script;
|
||||
if(!script.load(lua_state, neroshop_config_name)) {
|
||||
return false;
|
||||
}
|
||||
neroshop::print("\033[1;94mloaded script \"" + script.get_file() + "\"");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool neroshop::create_config() {
|
||||
std::string user = neroshop::device::get_user();
|
||||
std::string text = "-- settings.lua\n"
|
||||
"localhost = \"127.0.0.1\";\n"
|
||||
"neroshop = {};\n"
|
||||
"neroshop[\"currency\"] = \"usd\";\n"//\n"
|
||||
"\n"
|
||||
"neroshop[\"window\"] = {};\n"
|
||||
//"--neroshop[\"window\"][\"x\"] = 200;\n"
|
||||
//"--neroshop[\"window\"][\"y\"] = 200;\n"
|
||||
"neroshop[\"window\"][\"width\"] = 1280;\n"
|
||||
"neroshop[\"window\"][\"height\"] = 720;\n"
|
||||
"neroshop[\"window\"][\"mode\"] = 0; --0 (window_mode) or 1 (fullscreen)\n"//\n"
|
||||
"\n"
|
||||
"neroshop[\"monerod\"] = {};\n" // maybe change name from daemon to node or nah?
|
||||
"neroshop[\"monerod\"][\"network_type\"] = \"stagenet\"; --\"mainnet\", \"stagenet\", or \"testnet\"\n"
|
||||
"neroshop[\"monerod\"][\"ip\"] = localhost; -- set to \"0.0.0.0\" to allow other wallets to connect to your node\n"
|
||||
"neroshop[\"monerod\"][\"port\"] = \"38081\"; --\"18081\" (mainnet), \"38081\" (stagenet), or 28081 (testnet)\n"
|
||||
"neroshop[\"monerod\"][\"confirm_external_bind\"] = false; -- if true then it confirms that you want to allow connections from other wallets outside of this system, but only when ip is set to \"0.0.0.0\"\n"
|
||||
"neroshop[\"monerod\"][\"restricted_rpc\"] = true;\n"
|
||||
"neroshop[\"monerod\"][\"data_dir\"] = \"/home/<user>/.bitmonero\";\n"
|
||||
"neroshop[\"monerod\"][\"remote\"] = false; -- set to true if the node that you want to connect to is a remote node\n"//\n"
|
||||
"\n"
|
||||
"neroshop[\"wallet\"] = {};\n"
|
||||
"neroshop[\"wallet\"][\"file\"] = \"\"; -- include \".keys\" extension\n" // path or file
|
||||
"neroshop[\"wallet\"][\"restore_height\"] = \"2014-04-18\"; -- block height or date (YYYY-MM-DD)\n";
|
||||
// swap data_dir with user
|
||||
#if defined(__gnu_linux__) // works!
|
||||
text = neroshop::string::swap_first_of(text, "/home/<user>/.bitmonero", ("/home/" + user + "/.bitmonero"));
|
||||
#endif
|
||||
// "/home/<user>/.config/neroshop"
|
||||
#if defined(NEROSHOP_USE_QT)
|
||||
std::string neroshop_config_path = NEROSHOP_DEFAULT_CONFIGURATION_PATH.toStdString();
|
||||
#else
|
||||
std::string neroshop_config_path = NEROSHOP_DEFAULT_CONFIGURATION_PATH;//"/home/" + user + "/.config/neroshop"; // neroshop::device::get_user()
|
||||
#endif
|
||||
// "/home/<user>/.config/neroshop/config.lua"
|
||||
std::string neroshop_config_name = neroshop_config_path + "/" + NEROSHOP_CONFIGURATION_FILE;
|
||||
// if file already exists, no need to create it again
|
||||
if(std::filesystem::is_regular_file(neroshop_config_name)) return false; // false because it will not be created // if true then it will cause "PANIC: unprotected error in call to Lua API (attempt to index a nil value)" error
|
||||
// check if script works before saving
|
||||
if(luaL_dostring(lua_state, text.c_str()) != 0) {
|
||||
neroshop::print(LUA_TAG "\033[0;91minvalid Lua code");
|
||||
lua_error(lua_state);
|
||||
return false; // exit function so it does not save text
|
||||
}
|
||||
// if path does not exist
|
||||
if(!std::filesystem::is_directory(neroshop_config_path))
|
||||
{ // create the path
|
||||
neroshop::print("directory \"" + neroshop_config_path + "\" does not exist, but I will create it for you (^_^)", 2);
|
||||
if(!std::filesystem::create_directories(neroshop_config_path)) { neroshop::print("create_config error: failed to make the path. Sorry (ᵕ人ᵕ)! ...", 1); return false; }
|
||||
neroshop::print("\033[1;97;49mcreated path \"" + neroshop_config_path + "\"");
|
||||
}
|
||||
// if path exists, but the file is missing or deleted
|
||||
if(!std::filesystem::is_regular_file(neroshop_config_name)) {
|
||||
// create config file (one time)
|
||||
std::ofstream cfg;
|
||||
cfg.open (neroshop_config_name, std::ios::out | std::ios::trunc);
|
||||
cfg << text << "\n"; // write to file
|
||||
cfg.close();
|
||||
neroshop::print("\033[1;97;49mcreated file \"" + neroshop_config_name + "\"\033[0m");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//////////////////////////////
|
||||
//void neroshop::edit_config(const std::string& old_str, const std::string& new_str); // not possible to edit lua files with my current knowledge
|
||||
|
||||
extern bool neroshop::open_config() {
|
||||
if(!neroshop::create_config()) {
|
||||
if(!neroshop::load_config()) {
|
||||
neroshop::print("Failed to load configuration file", 1);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool neroshop::create_configuration_file() {
|
||||
return neroshop::create_config();
|
||||
}
|
||||
|
||||
bool neroshop::load_configuration_file() {
|
||||
return neroshop::load_config();
|
||||
}
|
||||
|
||||
bool neroshop::open_configuration_file() {
|
||||
return neroshop::open_config();
|
||||
}
|
||||
|
||||
lua_State * neroshop::get_lua_state() {
|
||||
return lua_state;
|
||||
}
|
@ -1,62 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>MainWindow</class>
|
||||
<widget class="QMainWindow" name="MainWindow">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>243</width>
|
||||
<height>111</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Hello, World!</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralWidget">
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="pixmap">
|
||||
<pixmap resource="resources.qrc">:/resources/helloworld-transparent.png</pixmap>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QMenuBar" name="menuBar">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>243</width>
|
||||
<height>21</height>
|
||||
</rect>
|
||||
</property>
|
||||
<widget class="QMenu" name="menuFile">
|
||||
<property name="title">
|
||||
<string>&File</string>
|
||||
</property>
|
||||
<addaction name="actionExit"/>
|
||||
</widget>
|
||||
<addaction name="menuFile"/>
|
||||
</widget>
|
||||
<widget class="QStatusBar" name="statusBar"/>
|
||||
<action name="actionExit">
|
||||
<property name="text">
|
||||
<string>E&xit</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11"/>
|
||||
<resources>
|
||||
<include location="resources.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in new issue