Add qml/ and other changes

pull/21/head
larteyoh 2 years ago
parent be4fee03ce
commit 4ecc44ab85

@ -57,11 +57,11 @@ endif()
if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
# Set compiler-specific flags
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -w -fsanitize=address") #-w=ignores all warnings
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -w")# -fsanitize=address") #-w=ignores all warnings
message(STATUS "Building with clang")
else()
message(STATUS "Building with gcc/g++")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -no-pie -fsanitize=address") # -no-pie=detach from terminal
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -no-pie")# -fsanitize=address") # -no-pie=detach from terminal
endif()
endif()
@ -124,7 +124,6 @@ set(Boost_USE_MULTITHREADED ON)
find_package(Boost 1.58 QUIET REQUIRED COMPONENTS chrono date_time filesystem program_options regex serialization wserialization system thread)
message(STATUS "Using Boost include dir at ${Boost_INCLUDE_DIR}")
include_directories(${Boost_INCLUDE_DIR})
#add_definitions(-DBOOST_BIND_GLOBAL_PLACEHOLDERS) # to ignore warnings # remove this
######################################
# OpenSSL
@ -315,32 +314,22 @@ ${UNBOUND_LIBRARIES} ${Boost_LIBRARIES} ${Protobuf_LIBRARY} ${LibUSB_LIBRARIES}
######################################
# monero-cpp (wrapper)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/external/monero-cpp/src/)
set(monero_cpp_src ${CMAKE_CURRENT_SOURCE_DIR}/build/libmonero-cpp.a)#set(monero_cpp_src external/monero-cpp/src/utils/gen_utils.cpp external/monero-cpp/src/utils/monero_utils.cpp external/monero-cpp/src/daemon/monero_daemon_model.cpp external/monero-cpp/src/daemon/monero_daemon.cpp external/monero-cpp/src/wallet/monero_wallet_model.cpp external/monero-cpp/src/wallet/monero_wallet_keys.cpp external/monero-cpp/src/wallet/monero_wallet_full.cpp)
set(monero_cpp_src ${CMAKE_CURRENT_SOURCE_DIR}/build/libmonero-cpp.a)
######################################
# libbcrypt (optional)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/external/libbcrypt)
set(bcrypt_src ${CMAKE_CURRENT_SOURCE_DIR}/build/libbcrypt.a)#set(bcrypt_src external/libbcrypt/crypt_blowfish/crypt_blowfish.c external/libbcrypt/crypt_blowfish/crypt_gensalt.c external/libbcrypt/crypt_blowfish/wrapper.c external/libbcrypt/bcrypt.c)
set(bcrypt_src ${CMAKE_CURRENT_SOURCE_DIR}/build/libbcrypt.a)
######################################
# sqlite3 (will be built-in/bundled with neroshop)
#[[find_package(SQLite3)
if(SQLite3_FOUND)
message(STATUS "Using SQLite3: ${SQLite3_LIBRARY} (v${SQLite3_VERSION})")
include_directories(${SQLite3_INCLUDE_DIRS})
set(sqlite_src ${SQLite3_LIBRARY}) # or ${SQLite3_LIBRARIES}
endif()
if(NOT SQLite3_FOUND)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/external/sqlite)
set(sqlite_src ${CMAKE_CURRENT_SOURCE_DIR}/external/sqlite/sqlite3.c) # amalgamation - runs a bit faster
endif()]]
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/external/sqlite)
set(sqlite_src ${CMAKE_CURRENT_SOURCE_DIR}/build/libsqlite3.a)#set(sqlite_src ${CMAKE_CURRENT_SOURCE_DIR}/external/sqlite/sqlite3.c)
# sqlite3
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/external/sqlite) # v3.39.1 (amalgamation - said to run a bit faster)
set(sqlite_src ${CMAKE_CURRENT_SOURCE_DIR}/build/libsqlite3.a)
######################################
# QR-Code-generator
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/external/QR-Code-generator/cpp)
set(qr_code_generator_src ${CMAKE_CURRENT_SOURCE_DIR}/build/libqrcodegen.a)#set(qr_code_generator_src ${CMAKE_CURRENT_SOURCE_DIR}/external/QR-Code-generator/cpp/qrcodegen.cpp) # or ${CMAKE_CURRENT_SOURCE_DIR}/external/QR-Code-generator/c/qrcodegen.c
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/external/QR-Code-generator/cpp) # v1.8.0
set(qr_code_generator_src ${CMAKE_CURRENT_SOURCE_DIR}/build/libqrcodegen.a)
######################################
# json
@ -348,7 +337,7 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR}/external/json/single_include)
######################################
# curl
find_package(CURL) # if curl is found on the system, use the system default shared library, otherwise use the curl that we've built from source
find_package(CURL)
if(CURL_FOUND)
message(STATUS "Using CURL: ${CURL_LIBRARIES} (v${CURL_VERSION_STRING})")
include_directories(${CURL_INCLUDE_DIRS})
@ -356,13 +345,13 @@ if(CURL_FOUND)
endif()
if(NOT CURL_FOUND)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/external/curl/include ${CMAKE_CURRENT_SOURCE_DIR}/external/curl/lib)
set(curl_src ${CMAKE_CURRENT_SOURCE_DIR}/external/curl/lib/.libs/libcurl.a)
set(curl_src ${CMAKE_CURRENT_SOURCE_DIR}/external/curl/lib/.libs/libcurl.a) # In case user chooses to build libcurl themselves instead of installing it on the system
add_definitions(-DCURL_STATICLIB)
set(CMAKE_CXX_LINK_EXECUTABLE "${CMAKE_CXX_LINK_EXECUTABLE} -lldap -llber -lnghttp2 -lpsl -lidn2 -lbrotlidec -lzstd -lrtmp") # for Arch (Manjaro) # https://stackoverflow.com/questions/68368557/linking-nghttp2-static-library#comment120830125_68368557
set(CMAKE_CXX_LINK_EXECUTABLE "${CMAKE_CXX_LINK_EXECUTABLE} -lldap -llber -lnghttp2 -lpsl -lidn2 -lbrotlidec -lzstd -lrtmp") # for Arch (Manjaro)
endif()
######################################
# libuv (supports Android :D)
# libuv
find_package(LibUV)
if(LIBUV_FOUND)
message(STATUS "Using LibUV: ${LibUV_LIBRARIES} (v${LibUV_VERSION})")
@ -375,16 +364,16 @@ if(NOT LIBUV_FOUND)
endif()
######################################
# willemt/raft (BSD and has zero dependencies :D)
# willemt/raft
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/external/raft/include)
set(raft_src ${CMAKE_CURRENT_SOURCE_DIR}/build/libraft.a)#set(raft_src ${CMAKE_CURRENT_SOURCE_DIR}/external/raft/src/raft_log.c ${CMAKE_CURRENT_SOURCE_DIR}/external/raft/src/raft_node.c ${CMAKE_CURRENT_SOURCE_DIR}/external/raft/src/raft_server.c ${CMAKE_CURRENT_SOURCE_DIR}/external/raft/src/raft_server_properties.c)
set(raft_src ${CMAKE_CURRENT_SOURCE_DIR}/build/libraft.a)
######################################
# stduuid (header-only MIT library for generating uuids)
# stduuid
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/external/stduuid ${CMAKE_CURRENT_SOURCE_DIR}/external/stduuid/catch ${CMAKE_CURRENT_SOURCE_DIR}/external/stduuid/include)
######################################
# linenoise (BSD replacement for GNU readline)
# linenoise
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/external/linenoise/)
set(linenoise_src ${CMAKE_CURRENT_SOURCE_DIR}/build/liblinenoise.a)
@ -397,7 +386,11 @@ set(lua_src ${CMAKE_CURRENT_SOURCE_DIR}/build/liblua.a)
# png (needs zlib)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/external/png/) # v1.6.37
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/external/zlib/) #v1.2.12
set(png_src ${CMAKE_CURRENT_SOURCE_DIR}/build/libpng.a ${CMAKE_CURRENT_SOURCE_DIR}/build/libz.a)
if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
set(png_src ${CMAKE_CURRENT_SOURCE_DIR}/build/libpng.so ${CMAKE_CURRENT_SOURCE_DIR}/build/libz.a) # Linux requires libpng to be built dynamically to prevent the Gtk:ERROR: ... "Failed to load /usr/share/icons/Yaru/16x16/status/image-missing.png: Fatal error reading PNG image file: Invalid IHDR data (gdk-pixbuf-error-quark, 0)" when opening the QML FileDialog
else()
set(png_src ${CMAKE_CURRENT_SOURCE_DIR}/build/libpng.a ${CMAKE_CURRENT_SOURCE_DIR}/build/libz.a)
endif()
######################################
# dokun-ui
@ -435,7 +428,7 @@ link_directories(${CMAKE_CURRENT_SOURCE_DIR}/build) # target_link_directories on
######################################
# neroshop core source files
set(neroshop_src src/buyer.cpp #[[src/carrier.cpp]] src/cart.cpp src/catalog.cpp src/client.cpp src/converter.cpp src/database.cpp src/encryptor.cpp #[[src/icon.cpp]] src/item.cpp #[[src/main.cpp]] src/order.cpp src/process.cpp src/qr.cpp src/script.cpp src/seller.cpp src/server.cpp src/user.cpp src/validator.cpp src/wallet.cpp)
set(neroshop_src src/buyer.cpp #[[src/carrier.cpp]] src/cart.cpp src/catalog.cpp src/client.cpp src/config.cpp src/converter.cpp src/database.cpp src/encryptor.cpp #[[src/icon.cpp]] src/item.cpp #[[src/main.cpp]] src/order.cpp src/process.cpp src/qr.cpp src/script.cpp src/seller.cpp src/server.cpp src/user.cpp src/validator.cpp src/wallet.cpp)
######################################
# neroshop tests

@ -41,10 +41,10 @@ Coming soon
| [libuv](https://github.com/libuv/libuv) | ? | networking and child process | :heavy_check_mark: |
| [raft](https://github.com/willemt/raft) | ? | consensus mechanism | :heavy_check_mark: |
| [stduuid](https://github.com/mariusbancila/stduuid) | ? | order number generation | :heavy_check_mark: |
| [linenoise](https://github.com/antirez/linenoise) | ? | command line interface | :heavy_check_mark: |
| [linenoise](https://github.com/antirez/linenoise) | ? | command line interface | :heavy_check_mark: :o: |
### Compiling neroshop from source
**0. Clone neroshop**
**0. Clone neroshop (and its submodules)**
```bash
git clone --recurse-submodules https://github.com/larteyoh/testshop.git && cd testshop
```
@ -57,11 +57,11 @@ Debian/Ubuntu
# prerequisites
sudo apt install build-essential cmake git
# neroshop
sudo apt install libx11-dev libgl1-mesa-dev libglu1-mesa-dev libglfw3-dev libcurl4-openssl-dev libssl-dev libuv1-dev qtdeclarative5-dev qml-module-qt-labs-platform qml-module-qtquick-controls qml-module-qtquick-controls2
sudo apt install libx11-dev libgl1-mesa-dev libglu1-mesa-dev libglfw3-dev libcurl4-openssl-dev libssl-dev libuv1-dev qtdeclarative5-dev qml-module-qt-labs-platform qml-module-qtquick-controls qml-module-qtquick-controls2 qml-module-qtquick-shapes
# monero-cpp (monero)
sudo apt update && sudo apt install pkg-config libssl-dev libzmq3-dev libsodium-dev libunwind8-dev liblzma-dev libreadline6-dev libpgm-dev qttools5-dev-tools libhidapi-dev libusb-1.0-0-dev libprotobuf-dev protobuf-compiler libudev-dev libboost-chrono-dev libboost-date-time-dev libboost-filesystem-dev libboost-locale-dev libboost-program-options-dev libboost-regex-dev libboost-serialization-dev libboost-system-dev libboost-thread-dev python3 ccache
```
Arch
Arch (needs to be updated)
```bash
# prerequisites
sudo pacman -Sy --needed base-devel cmake git
@ -70,7 +70,7 @@ sudo pacman -Sy --needed libx11 lib32-mesa lib32-glu curl openssl libuv
# monero-cpp (monero)
sudo pacman -Syu --needed boost openssl zeromq libpgm libsodium libunwind xz readline gtest python3 ccache qt5-tools hidapi libusb protobuf systemd
```
Fedora
Fedora (needs to be updated)
```bash
# prerequisites
sudo dnf install gcc gcc-c++ make cmake git
@ -185,7 +185,7 @@ To build for [Android](https://www.android.com/) (requires [Android NDK](https:/
[//]: # (./clean.sh)
[//]: # (git checkout -b main)
[//]: # (git add .gitignore .gitmodules cmake/ CMakeLists.txt external/ main.qml premake5.lua README.md res/neroshop-logo.png res/wallets src/ test/)
[//]: # (git add .gitignore .gitmodules cmake/ CMakeLists.txt external/ qml/ main.qml premake5.lua README.md res/neroshop-logo.png res/wallets src/ test/)
[//]: # (git commit -m"...")
[//]: # (git push -u origin main --force)
[//]: # (https://git.slipfox.xyz/larteyoh/testshop/settings => Mirror Settings => Synchronize Now)

@ -52,7 +52,11 @@ target_include_directories(${lua_target} PUBLIC lua/src/)
set(png_target "png")
set(png_srcs png/png.c png/pngerror.c png/pngget.c png/pngmem.c png/pngpread.c png/pngread.c png/pngrio.c png/pngrtran.c png/pngrutil.c png/pngset.c #[[png/pngtest.c]] png/pngtrans.c png/pngwio.c png/pngwrite.c png/pngwtran.c png/pngwutil.c)
add_library(${png_target} STATIC ${png_srcs})
if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
add_library(${png_target} SHARED ${png_srcs}) # Linux requires libpng to be built dynamically to fix the Gtk:ERROR: ... "Failed to load /usr/share/icons/Yaru/16x16/status/image-missing.png: Fatal error reading PNG image file: Invalid IHDR data (gdk-pixbuf-error-quark, 0)" when opening the QML FileDialog
else()
add_library(${png_target} STATIC ${png_srcs})
endif()
target_include_directories(${png_target} PUBLIC png/)
set(zlib_target "zlib") # required by png

@ -1,19 +1,27 @@
// 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 // TextField, TextArea (multi-lined TextField), TextFieldStyle//import QtQuick.Controls.Material 2.12 // Other styles:
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.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)
// custom modules
////import neroshop.Wallet 1.0
import Qt.labs.platform 1.1 // FileDialog (since Qt 5.8) // change to "import QtQuick.Dialogs" if using Qt 6.2
//import neroshop.FileDialog 1.0 // todo:check if custom module exists before impoorting it since its only available on linux
//import neroshop.Wallet 1.0
import "qml/components"
import "qml/components" as NeroshopComponents
import "qml/pages"
ApplicationWindow {
id: window
visible: true // By default, an ApplicationWindow is not visible, so we have to set visible to true
title: qsTr("neroshop v" + neroshopVersion)
id: main_window
visible: true
title: qsTr("neroshop" + " v" + neroshopVersion)
width: 1280
height: 720
minimumWidth: 750
minimumHeight: 450
color: '#202020'
/*style: ApplicationWindowStyle {
background: BorderImage {
@ -33,419 +41,51 @@ ApplicationWindow {
// ...
} */
/*StackView { // This would be good for pages that can be stacked on top of each other
id: home_menu
/*StackView { // This would be good for subpages that can be stacked on top of each other
id: home_stackview
anchors.fill: parent // will fill entire Window area
initialItem: auth_stack
////initialItem: page_loader
//currentItem:
}*/
///////////////////////////
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");
/*NeroshopComponents.Hint {
id: hint
visible: false
}*/
NeroshopComponents.SearchBar {
visible: (!page_loader.source.toString().match("qml/pages/MainPage.qml")) ? true : false;
}
///////////////////////////
//Wallet {
// id: wallet
//}
///////////////////////////
function generate_keys() {
// generate a unique wallet seed (mnemonic)
Wallet.create_random_wallet(wallet_password_create_edit.text, wallet_password_confirm_edit.text, neroshopDataDir + "/auth")//"wallet")
// if wallet passwords don't match, display error message
if(wallet_password_confirm_edit.text != wallet_password_create_edit.text) {
important_message_field.text = qsTr("Wallet passwords do not match")
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.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 = "";
}
NeroshopComponents.NavigationalBar {
visible: (!page_loader.source.toString().match("qml/pages/MainPage.qml")) ? true : false;
}
///////////////////////////
FileDialog {
id: wallet_file_dialog
fileMode: FileDialog.OpenFile
currentFile: wallet_upload_edit.text
folder: neroshopDataDir//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
}
// todo: create a top banner with a dot-styled pagination
///////////////////////////
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: 500
height: 300
x: window.width / 2 - width / 2 // window is the id of ApplicationWindow
y: window.height / 2 - height / 2
//Item {
Loader {
id: page_loader
anchors.centerIn: parent // place at center of parent
//anchors.fill: parent
source: "qml/pages/MainPage.qml"
//source: "qml/pages/HomePage.qml"
//source: "qml/pages/CatalogPage.qml"
//source: "qml/pages/ProductPage.qml"
//source: "qml/pages/OrderCheckoutPage.qml"
////source: "qml/pages/Page.qml"
// generate auth keys page
Rectangle {
id: genkey_page
color: "#a0a0a0"//'orange'
// optional pseudonym edit
// ...
// change wallet path edit
// ...
// wallet password create edit
TextField {
id: wallet_password_create_edit
placeholderText: qsTr("Wallet Password")
placeholderTextColor: "#696969" // dim gray
color: "#ff6600" // textColor - monero orange
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
y: generate_key_button.y
width: 300//; height: generate_key_button.height / 2
background: Rectangle {
color: "#4c4c4c"//#4c4c4c = monero gray color//"#404040" = 64, 64, 64
//border.color:"#ffffff"
}
// todo: maybe add a regex validator
}
// wallet password confirm edit
TextField {
id: wallet_password_confirm_edit
placeholderText: qsTr("Confirm Wallet Password")
placeholderTextColor: "#696969" // dim gray
color: "#ff6600" // textColor - monero orange
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: "#4c4c4c"
//border.color:"#ffffff"
}
}
// generate key button
Button {
id: generate_key_button
text: qsTr("Generate keys")
x: 20
y: 20
height: 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 - 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: 300
height: 150//200
x: generate_key_button.x//20
y: (important_message_field.visible) ? important_message_field.y + important_message_field.height + 10 : generate_key_button.y + generate_key_button.height + 20//genkey_page.height - this.height - 20
TextArea {
id: seed_display_edit
readOnly: true
//text: qsTr("hefty value later extra artistic firm radar yodel talent future fungal nutshell\nbecause sanity awesome nail unjustly rage unafraid cedar delayed thumbs\ncomb custom sanity")// temp
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: 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
y: seed_display_scrollview.y + (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
/*contentItem: Image {
source: neroshopResourceDir + "/copy.png"
height: 24; width: 24 // has no effect since image is scaled
fillMode:Image.PreserveAspectFit;
}*/
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'
onSourceChanged: {
console.log(source);
if (page_loader.status == Loader.Ready) console.log('Loaded')
else console.log('Not Loaded')
}
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: "#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: "#4c4c4c"
}
}
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"
}
}
}
//}
// navigating between different pages: https://stackoverflow.com/a/15655043
// Page does not render the title itself, but instead relies on the application to do so
/*header: Label {
text: main_page.title
horizontalAlignment: Text.AlignHCenter
}*/
}
// error: module "QtQuick.Layouts" version 1.15 is not installed (fix by changing the version specified in /usr/lib/x86_64-linux-gnu/qt5/qml/QtQuick/Layouts/plugins.qmltypes)
// error: module "Qt.labs.platform" is not installed (fix: sudo apt install qml-module-qt-labs-platform)
@ -454,4 +94,5 @@ ApplicationWindow {
// install: qtbase5-dev for "../cmake/Qt5/Qt5Config.cmake"
// error: /usr/lib/x86_64-linux-gnu/cmake/Qt5/Qt5Config.cmake will set Qt5_FOUND to FALSE so package "Qt5" is considered to be NOT FOUND due to Qml and Quick configuration files (/usr/lib/x86_64-linux-gnu/cmake/Qt5Qml/Qt5QmlConfig.cmake; /usr/lib/x86_64-linux-gnu/cmake/Qt5Quick/Qt5QuickConfig.cmake) not being found (fix: sudo apt install qtdeclarative5-dev)
// error: module "QtQuick" is not installed (fix: qml-module-qtquick-controls qml-module-qtquick-controls2). This will also install qml-module-qtgraphicaleffects, qml-module-qtquick-layouts, qml-module-qtquick-window2, and qml-module-qtquick2
// error: module "QtQuick.Shapes" is not installed (fix: qml-module-qtquick-shapes)

@ -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;
}

@ -3,33 +3,39 @@
#ifndef CONFIG_HPP_NEROSHOP
#define CONFIG_HPP_NEROSHOP
#define LUA_TAG "\033[1;34m[lua]:\033[0m "
// configuration dir(s)
// windows
#if defined(NEROSHOP_USE_QT)
#include <QStandardPaths>
#define NEROSHOP_DEFAULT_CONFIGURATION_PATH QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation)
#endif
#if !defined(NEROSHOP_USE_QT)
#if defined(_WIN32)
#define NEROSHOP_CONFIG_PATH "C:/ProgramData/neroshop"//"C:/Users/<USER>/AppData/Local/<APPNAME>", "C:/ProgramData/<APPNAME>" (AppConfigLocation)
#define NEROSHOP_DEFAULT_CONFIGURATION_PATH "C:/Users/" + neroshop::device::get_user() + "/AppData/Local/neroshop"
#define NEROSHOP_DEFAULT_CONFIGURATION_PATH_ALT "C:/ProgramData/neroshop"
#endif
// linux
#if defined(__linux__) && !defined(__ANDROID__)
#define NEROSHOP_CONFIG_PATH "/home/" + neroshop::device::get_user() + "/.config/neroshop"//"~/.config/<APPNAME>", "/etc/xdg/<APPNAME>" (AppConfigLocation)
#define NEROSHOP_DEFAULT_CONFIGURATION_PATH "/home/" + neroshop::device::get_user() + "/.config/neroshop"
#define NEROSHOP_DEFAULT_CONFIGURATION_PATH_ALT "/etc/xdg/neroshop"
#endif
// macos
#if defined(__APPLE__) && defined(__MACH__)
#define NEROSHOP_CONFIG_PATH "~/Library/Preferences/neroshop"//"~/Library/Preferences/<APPNAME>" (AppConfigLocation)
//#define NEROSHOP_DEFAULT_CONFIGURATION_PATH "~/Library/Preferences/neroshop"
#endif
// android
#if defined(__ANDROID__)
//"<APPROOT>/files/settings" (AppConfigLocation)
//#define NEROSHOP_DEFAULT_CONFIGURATION_PATH "<APPROOT>/files/settings"
#endif
// iOS
#if defined(__APPLE__)
#include <TargetConditionals.h>
#if TARGET_OS_IPHONE
//"<APPROOT>/Library/Preferences/<APPNAME>" (AppConfigLocation)
//#define NEROSHOP_DEFAULT_CONFIGURATION_PATH "<APPROOT>/Library/Preferences/neroshop"
#endif
#endif
#endif // endif !defined(NEROSHOP_USE_QT)
#define NEROSHOP_CONFIG_FILE "config.lua"
#define NEROSHOP_CONFIGURATION_NAME "settings"
#define NEROSHOP_CONFIGURATION_EXTENSION "lua"
#define NEROSHOP_CONFIGURATION_FILE NEROSHOP_CONFIGURATION_NAME "." NEROSHOP_CONFIGURATION_EXTENSION
#define LUA_TAG "\033[1;34m[lua]:\033[0m "
#include "script.hpp"//<script.hpp>
#include <filesystem>
@ -38,83 +44,17 @@
#include "debug.hpp"
namespace neroshop {
extern lua_State * lua_state;// (luaL_newstate());//(nullptr);// extern is for declaration in .h and then defined in a .cpp file
//////////////////////////////
static bool load_config() {
std::string user = neroshop::device::get_user();
// "/home/<user>/.config/neroshop"
std::string neroshop_config_path = NEROSHOP_CONFIG_PATH;//"/home/" + user + "/.config/neroshop";
// "/home/<user>/.config/neroshop/config.lua"
std::string neroshop_config_name = neroshop_config_path + "/" + NEROSHOP_CONFIG_FILE;
Script script;
if(!script.load(lua_state, neroshop_config_name)) {return false;}
neroshop::print("\033[1;94mloaded script \"" + script.get_file() + "\"");
return true; // default return-value
}
//////////////////////////////
static bool create_config() {
std::string user = neroshop::device::get_user();
std::string text = "-- config.lua\n"
"localhost = \"127.0.0.1\";\n"
"neroshop = {};\n"
"neroshop[\"currency\"] = \"usd\";\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"
"neroshop[\"daemon\"] = {};\n" // maybe change name from daemon to node or nah?
"neroshop[\"daemon\"][\"network_type\"] = \"stagenet\"; --\"mainnet\", \"stagenet\", or \"testnet\"\n"
"neroshop[\"daemon\"][\"ip\"] = localhost; -- set to \"0.0.0.0\" to allow other wallets to connect to your node\n"
"neroshop[\"daemon\"][\"port\"] = \"38081\"; --\"18081\" (mainnet), \"38081\" (stagenet), or 28081 (testnet)\n"
"neroshop[\"daemon\"][\"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[\"daemon\"][\"restricted_rpc\"] = true;\n"
"neroshop[\"daemon\"][\"data_dir\"] = \"/home/<user>/.bitmonero\";\n"
"neroshop[\"daemon\"][\"remote\"] = false; -- set to true if the node that you want to connect to is a remote node\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"
std::string neroshop_config_path = NEROSHOP_CONFIG_PATH;//"/home/" + user + "/.config/neroshop"; // neroshop::device::get_user()
// "/home/<user>/.config/neroshop/config.lua"
std::string neroshop_config_name = neroshop_config_path + "/" + NEROSHOP_CONFIG_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;
}
//////////////////////////////
//static void edit_config(const std::string& old_str, const std::string& new_str); // not possible to edit lua files with my current knowledge
//////////////////////////////
static lua_State * get_lua_state() {
return lua_state;
}
extern lua_State * lua_state;
extern bool create_config();
extern bool load_config();
extern bool open_config(); // create_config + load_config
//static void edit_config(const std::string& old_str, const std::string& new_str); // not sure how to edit lua files with my current knowledge
// alternative function names
extern bool create_configuration_file();
extern bool load_configuration_file();
extern bool open_configuration_file(); // create_config + load_config
extern lua_State * get_lua_state();
}
#endif

@ -1,8 +1,23 @@
#ifndef DATABASE_HPP_NEROSHOP
#define DATABASE_HPP_NEROSHOP
#define NEROSHOP_DATABASE_PATH ""//#define NEROSHOP_DATABASE_NAME "data"
#define NEROSHOP_DATABASE_FILE "data.sqlite3"
#if defined(NEROSHOP_USE_QT)
#include <QStandardPaths>
#define NEROSHOP_DEFAULT_DATABASE_PATH QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation) //(QStandardPaths::AppLocalDataLocation)
#endif
#if !defined(NEROSHOP_USE_QT)
#if defined(__linux__) && !defined(__ANDROID__)
#define NEROSHOP_DEFAULT_DATABASE_PATH "/home/" + neroshop::device::get_user() + "/.config/neroshop" //"/home/" + neroshop::device::get_user() + "/.local/share/neroshop"
#endif
#if defined(_WIN32)
#define NEROSHOP_DEFAULT_DATABASE_PATH "C:/Users/" + neroshop::device::get_user() + "/AppData/Local/neroshop"
#endif
#endif // endif !defined(NEROSHOP_USE_QT)
#define NEROSHOP_DATABASE_NAME "data"
#define NEROSHOP_DATABASE_EXTENSION "sqlite3"
#define NEROSHOP_DATABASE_FILE NEROSHOP_DATABASE_NAME "." NEROSHOP_DATABASE_EXTENSION
#include "database/sqlite.hpp"

@ -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>&amp;File</string>
</property>
<addaction name="actionExit"/>
</widget>
<addaction name="menuFile"/>
</widget>
<widget class="QStatusBar" name="statusBar"/>
<action name="actionExit">
<property name="text">
<string>E&amp;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

@ -1,7 +1,7 @@
#ifndef ICON_HPP_NEROSHOP
#define ICON_HPP_NEROSHOP
#define NEROSHOP_RESOURCES_FOLDER "resources"
#define NEROSHOP_RESOURCES_FOLDER "resources/images" //"assets/images"
#define NEROSHOP_ASSETS_FOLDER NEROSHOP_RESOURCES_FOLDER
#include <png.h>
@ -46,6 +46,8 @@ private:
static bool load_link(); // names: "external_link", "link"
static bool load_shop();
static bool load_copy(); // names: "copy", "clipboard"
static bool load_views(); // names: "grid", "list"
static bool load_triangle();
//static bool load_();
// non-icons8 icons
static bool load_settings(); // cog//settings

@ -10,8 +10,8 @@
#include <QQmlApplicationEngine> // requires Qt5::Qml
#include <QQmlContext> // QQmlContext * QQmlApplicationEngine::rootContext()
//#include <QQuickView> // requires Qt5::Quick - we're not using QQuickView for now
#include <QStandardPaths>// requires Qt::Core
//#include <QMetaType> // requires Qt::Core
#include <QStandardPaths>// requires Qt::Core (since Qt 5.0)
#elif defined(NEROSHOP_USE_DOKUN_UI)
#include <dokun_ui.hpp>
using namespace dokun;
@ -22,29 +22,15 @@ using namespace dokun;
// neroshop (includes both the core headers and the gui headers)
#include "../neroshop.hpp"
using namespace neroshop;
lua_State * neroshop::lua_state = luaL_newstate();
//lua_State * neroshop::lua_state = luaL_newstate();
using WalletProxy = gui::Wallet;
int main(int argc, char *argv[]) {
// load all icon images
if(!Icon::load_all()) {
neroshop::print("Failed to load all icons", 1);
}
unsigned char * data = Icon::get<unsigned char *>("upload");
int size = Icon::get<int>("upload");
// Print icon information
std::cout << "Icon info (upload): \n" << "data=" << data << "\n" << "size=" << size << "\n";
////////////////////////////////////////////////////////
// create/load configuration script
if(!neroshop::create_config()) {
if(!neroshop::load_config()) {
neroshop::print("Failed to load config.lua", 1);
}
}
////////////////////////////////////////////////////////
#if defined(NEROSHOP_USE_QT)
std::cout << "Using Qt version: " << qVersion() << "\n";
// On Linux desktop, use QApplication since the Qt Labs Platform module uses Qt Widgets as a fallback on platforms that do not have a native platform file dialog implementation available. See https://doc.qt.io/qt-5/qml-qt-labs-platform-filedialog.html#availability
#if defined(__gnu_linux__) && defined(NEROSHOP_USE_QT_WIDGETS)
#if defined(NEROSHOP_USE_QT_WIDGETS)
QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QApplication app(argc, argv);
#else
@ -53,26 +39,45 @@ int main(int argc, char *argv[]) {
QQmlApplicationEngine engine;
//--------------------------
////////////////////////////////////////////////////////
// load all icon images
if(!Icon::load_all()) {
neroshop::print("Failed to load all icons", 1);
}
unsigned char * data = Icon::get<unsigned char *>("upload");
int size = Icon::get<int>("upload");
// Print icon information
std::cout << "Icon info (upload): \n" << "data=" << data << "\n" << "size=" << size << "\n";
////////////////////////////////////////////////////////
// Configuration file must be loaded right after Qt Application object has been created so that we can get the correct config location
// open configuration script
neroshop::open_configuration_file();
// initialize (sync) database
// ...
////qRegisterMetaType<std::string>("std::string");
// custom macros
engine.rootContext()->setContextProperty("neroshopQtVersion", qVersion());
engine.rootContext()->setContextProperty("neroshopAppDirPath", QCoreApplication::applicationDirPath());
engine.rootContext()->setContextProperty("neroshopVersion", NEROSHOP_VERSION);
engine.rootContext()->setContextProperty("neroshopDataDir", QStandardPaths::writableLocation(QStandardPaths::HomeLocation) + "/neroshop");//QStandardPaths::writableLocation(QStandardPaths::AppDataLocation));
engine.rootContext()->setContextProperty("neroshopConfigDir", QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation));
engine.rootContext()->setContextProperty("neroshopWalletDir", NEROSHOP_DEFAULT_WALLET_PATH);//QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation));
engine.rootContext()->setContextProperty("neroshopDataDir", NEROSHOP_DEFAULT_DATABASE_PATH);
engine.rootContext()->setContextProperty("neroshopConfigDir", NEROSHOP_DEFAULT_CONFIGURATION_PATH);
engine.rootContext()->setContextProperty("neroshopResourceDir", QCoreApplication::applicationDirPath() + "/" + NEROSHOP_RESOURCES_FOLDER); // defined in icon.hpp
// create neroshop directories - datadir and configdir
if(!std::filesystem::is_directory( (QStandardPaths::writableLocation(QStandardPaths::HomeLocation) + "/neroshop").toStdString() )) {
neroshop::print(std::string("Creating directory \"") + (QStandardPaths::writableLocation(QStandardPaths::HomeLocation) + "/neroshop").toStdString() + "\"", 3);
if(!std::filesystem::create_directories( (QStandardPaths::writableLocation(QStandardPaths::HomeLocation) + "/neroshop").toStdString() )) {
if(!std::filesystem::is_directory(NEROSHOP_DEFAULT_WALLET_PATH.toStdString())) {
neroshop::print(std::string("Creating directory \"") + NEROSHOP_DEFAULT_WALLET_PATH.toStdString() + "\"", 3);
if(!std::filesystem::create_directories(NEROSHOP_DEFAULT_WALLET_PATH.toStdString())) {
throw std::runtime_error("Failed to create neroshop datadir");
return 1;
}
}
// register custom (class) modules
//qmlRegisterSingletonType(QUrl("qml/style.qml"), "neroshop.Styles", 1, 0, "style");
////qmlRegisterType<neroshop::gui::Wallet/*WalletProxy*/>("neroshop.Wallet", 1, 0, "Wallet"); // Usage: import neroshop.Wallet ... Wallet { id: wallet }
// we can also register an instance of a class instead of the class itself
//gui::Wallet wallet;
engine.rootContext()->setContextProperty("Wallet", new gui::Wallet()/*WalletProxy()*/);
engine.rootContext()->setContextProperty("Wallet", new WalletProxy());//qmlRegisterUncreatableType<WalletProxy>("neroshop.Wallet", 1, 0, "Wallet", "Wallet cannot be instantiated directly.");
//--------------------------
engine.load("../main.qml");//("main.qml");
if (engine.rootObjects().isEmpty()) {

@ -20,9 +20,9 @@ neroshop::Wallet * neroshop::gui::Wallet::get_wallet() const {
return wallet.get();
}
void neroshop::gui::Wallet::create_random_wallet(const QString& password, const QString& confirm_pwd, const QString& path) {//const {
// if the wallet already exists then this will crash so we must check if wallet exists first
wallet->create_random(password.toStdString(), confirm_pwd.toStdString(), path.toStdString());
int neroshop::gui::Wallet::create_random_wallet(const QString& password, const QString& confirm_pwd, const QString& path) const {
auto error = wallet->create_random(password.toStdString(), confirm_pwd.toStdString(), path.toStdString());
return static_cast<int>(error);
}
QString neroshop::gui::Wallet::get_mnemonic() const {

@ -24,7 +24,7 @@ class Wallet : public QObject {
public:
// functions (for use in QML)
////explicit Wallet(QObject* parent = 0);
Q_INVOKABLE void create_random_wallet(const QString& password, const QString& confirm_pwd, const QString& path);// const;
Q_INVOKABLE int create_random_wallet(const QString& password, const QString& confirm_pwd, const QString& path) const;
Q_INVOKABLE QString get_mnemonic() const;
Q_INVOKABLE neroshop::Wallet * get_wallet() const;
Q_INVOKABLE void set_wallet(const neroshop::Wallet* wallet/*const neroshop::Wallet& wallet*/) {}//const { /*this->wallet = const_cast<neroshop::Wallet*>(wallet);*//*this->wallet = &const_cast<neroshop::Wallet&>(wallet);*//*emit wallet_changed(status);*/ }

@ -32,7 +32,6 @@
#include "process.hpp"
// neroshop (gui)
#if defined(NEROSHOP_BUILD_GUI)
//#include "main_window.hpp" // already included in gui/main.cpp so there's no need to include this (I think?)
#include "gui/icon.hpp"
#include "gui/main_window.hpp"
#include "gui/message_box.hpp"

@ -30,20 +30,25 @@ neroshop::Wallet::~Wallet()
////////////////////
////////////////////
// Reminder: path is the path and name of the wallet without the .keys extension
void neroshop::Wallet::create_random(const std::string& password, const std::string& confirm_pwd, const std::string& path) {
neroshop::wallet_error neroshop::Wallet::create_random(const std::string& password, const std::string& confirm_pwd, const std::string& path) {
if(confirm_pwd != password) {
neroshop::print("Wallet passwords do not match", 1);
return;
return neroshop::wallet_error::PASSWORDS_NO_MATCH;
}
if(std::filesystem::is_regular_file(path + ".keys")) {
neroshop::print("Wallet file with the same name already exists", 1);
return neroshop::wallet_error::WALLET_ALREADY_EXISTS;
}
// configure wallet
/*monero::monero_wallet_config wallet_config_obj;
monero::monero_wallet_config wallet_config_obj;
wallet_config_obj.m_path = path;
wallet_config_obj.m_password = password;
wallet_config_obj.m_network_type = network_type;
// first argument is a "const monero_wallet_config &"
monero_wallet_obj = std::unique_ptr<monero_wallet_full>(monero_wallet_full::create_wallet (wallet_config_obj, nullptr));
*/
monero_wallet_obj = std::unique_ptr<monero_wallet_full>(monero_wallet_full::create_wallet_random (path, password, network_type/*, const monero_rpc_connection &daemon_connection=monero_rpc_connection(), const std::string &language="English", std::unique_ptr< epee::net_utils::http::http_client_factory > http_client_factory=nullptr*/)); // deprecated :(
////monero_wallet_obj = std::unique_ptr<monero_wallet_full>(monero_wallet_full::create_wallet_random (path, password, network_type/*, const monero_rpc_connection &daemon_connection=monero_rpc_connection(), const std::string &language="English", std::unique_ptr< epee::net_utils::http::http_client_factory > http_client_factory=nullptr*/)); // deprecated :(
if(monero_wallet_obj.get()) std::cout << "\033[1;35;49m" << "created wallet \"" << path << ".keys\"" << "\033[0m" << std::endl;
}
////////////////////

@ -3,16 +3,35 @@
#ifndef WALLET_HPP_NEROSHOP
#define WALLET_HPP_NEROSHOP
#define EXPLORER_XMRCHAIN "https://xmrchain.net/search?value="
#define EXPLORER_XMRCHAIN_MAINNET EXPLORER_XMRCHAIN
#define EXPLORER_XMRCHAIN_STAGENET "https://stagenet.xmrchain.net/search?value="
#define EXPLORER_XMRCHAIN_TESTNET "https://testnet.xmrchain.net/search?value="
#define EXPLORER_XMRCHAIN_TX "https://xmrchain.net/tx/"
#define EXPLORER_XMRCHAIN_MAINNET_TX EXPLORER_XMRCHAIN_TX
#define EXPLORER_XMRCHAIN_STAGENET_TX "https://stagenet.xmrchain.net/tx/"
#define EXPLORER_XMRCHAIN_TESTNET_TX "https://testnet.xmrchain.net/tx/"
#if defined(NEROSHOP_USE_QT)
#include <QStandardPaths>
#if defined(_WIN32)
#define NEROSHOP_DEFAULT_WALLET_PATH (QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation) + "/neroshop")
#else
#define NEROSHOP_DEFAULT_WALLET_PATH (QStandardPaths::writableLocation(QStandardPaths::HomeLocation) + "/neroshop")
#endif
#endif
#define NEROSHOP_DEFAULT_WALLET_PATH "/home/" + neroshop::device::get_user() + "/neroshop"//"/home/" + neroshop::device::get_user() + "/Monero/wallets"
#if !defined(NEROSHOP_USE_QT)
#if defined(__linux__) && !defined(__ANDROID__)
#define NEROSHOP_DEFAULT_WALLET_PATH "/home/" + neroshop::device::get_user() + "/neroshop"
#endif
#if defined(_WIN32)
#define NEROSHOP_DEFAULT_WALLET_PATH "C:/Users/" + neroshop::device::get_user() + "/Documents/neroshop"
#endif
#if defined(__APPLE__) && defined(__MACH__)
// ...
#endif
#if defined(__ANDROID__)
// ...
#endif
#if defined(__APPLE__)
#include <TargetConditionals.h>
#if TARGET_OS_IPHONE
// ...
#endif
#endif
#endif // endif !defined(NEROSHOP_USE_QT)
#include <daemon/monero_daemon.h>
#include <daemon/monero_daemon_model.h>
@ -28,17 +47,20 @@
#include <vector>
#include <utility> // std::pair
#include <cmath>
#include <filesystem>
#include "process.hpp" // for monerod daemon process
namespace neroshop {
// todo: maybe place enums in an "error.hpp" file or nah?
enum class wallet_error : int { WALLET_SUCCESS = 0, WRONG_PASSWORD, PASSWORDS_NO_MATCH, WALLET_ALREADY_EXISTS/*Wallet I/O Error*/ };
class Wallet : public monero_wallet_listener {
public:
Wallet();
~Wallet();
void create_random(const std::string& password, const std::string& confirm_pwd, const std::string& path);
/*void*/wallet_error create_random(const std::string& password, const std::string& confirm_pwd, const std::string& path);
void create_from_mnemonic(const std::string& mnemonic, const std::string& password, const std::string& confirm_pwd, const std::string& path);
void create_from_keys(const std::string& address, const std::string& view_key, const std::string& spend_key, const std::string& password, const std::string &confirm_pwd, const std::string& path);

Loading…
Cancel
Save