From 842345e57340668ba1b80784b17cee1c04781f65 Mon Sep 17 00:00:00 2001 From: Daniel Gretzke Date: Sun, 25 Aug 2019 02:59:15 +0200 Subject: [PATCH] Python GUI client for socket, initial commit --- .gitignore | 4 +- plug_py/credentials.py | 4 + plug_py/plug.py | 339 ++++++++++++++++++++++++++++++++ plug_py/qt/Plug_python.pro | 40 ++++ plug_py/qt/Plug_python.pro.user | 336 +++++++++++++++++++++++++++++++ plug_py/qt/main.cpp | 11 ++ plug_py/qt/mainwindow.cpp | 14 ++ plug_py/qt/mainwindow.h | 22 +++ plug_py/qt/mainwindow.ui | 259 ++++++++++++++++++++++++ plug_py/ui_mainwindow.py | 113 +++++++++++ 10 files changed, 1141 insertions(+), 1 deletion(-) create mode 100644 plug_py/credentials.py create mode 100644 plug_py/plug.py create mode 100644 plug_py/qt/Plug_python.pro create mode 100644 plug_py/qt/Plug_python.pro.user create mode 100644 plug_py/qt/main.cpp create mode 100644 plug_py/qt/mainwindow.cpp create mode 100644 plug_py/qt/mainwindow.h create mode 100644 plug_py/qt/mainwindow.ui create mode 100644 plug_py/ui_mainwindow.py diff --git a/.gitignore b/.gitignore index c220e3c..291411d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ /.vscode -build/ \ No newline at end of file +build/ +__pycache__/ +build-Plug_python-Desktop_Qt_5_13_0_clang_64bit-Debug/ \ No newline at end of file diff --git a/plug_py/credentials.py b/plug_py/credentials.py new file mode 100644 index 0000000..026f03b --- /dev/null +++ b/plug_py/credentials.py @@ -0,0 +1,4 @@ +nodeAddr = "Address of node" +privateKey = "Ethereum private key" +address = "Ethereum address belonging to private key" +IP = "IP (Websocket) Address of Smart Socket" diff --git a/plug_py/plug.py b/plug_py/plug.py new file mode 100644 index 0000000..c4e7c8e --- /dev/null +++ b/plug_py/plug.py @@ -0,0 +1,339 @@ +# ui libraries +from PySide2.QtWidgets import QApplication, QMainWindow, QScrollerProperties, QScroller +from PySide2.QtCore import QThread, QTimer, QObject, SIGNAL, SLOT +from PySide2 import QtGui +from ui_mainwindow import Ui_MainWindow + +# ethereum library +from web3 import Web3 + +# websockets +import asyncio +import websockets + +# utility libraries +import json +from json import JSONDecodeError +from enum import Enum +import sys + +# credentials +import credentials +nodeAddr = credentials.nodeAddr +contract_abi = '[{"constant":false,"inputs":[{"name":"_value","type":"uint256"},{"name":"_signature","type":"bytes"}],"name":"closeChannel","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"expirationDuration","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"balances","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"initializePaymentChannel","outputs":[{"name":"","type":"bool"}],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"customerNonces","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"pricePerSecond","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"withdraw","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"channelActive","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"minDeposit","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"creationTimeStamp","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"timeOutChannel","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"_value","type":"uint256"},{"name":"_signature","type":"bytes"}],"name":"verifySignature","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"expirationDate","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"maxValue","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"channelCustomer","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_newPrice","type":"uint256"}],"name":"changePrice","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"_pricePerSecond","type":"uint256"},{"name":"_expirationDuration","type":"uint256"},{"name":"_minDeposit","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"customer","type":"address"},{"indexed":true,"name":"start","type":"uint256"},{"indexed":true,"name":"maxValue","type":"uint256"},{"indexed":false,"name":"end","type":"uint256"}],"name":"InitializedPaymentChannel","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"sender","type":"address"},{"indexed":true,"name":"value","type":"uint256"},{"indexed":true,"name":"expired","type":"bool"},{"indexed":false,"name":"duration","type":"uint256"}],"name":"ClosedPaymentChannel","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"oldPrice","type":"uint256"},{"indexed":true,"name":"newPrice","type":"uint256"}],"name":"PriceChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"sender","type":"address"},{"indexed":true,"name":"amount","type":"uint256"}],"name":"Withdrawal","type":"event"}]' + +etherPriceEUR = 300 +web3 = Web3(Web3.HTTPProvider(nodeAddr)) + +privateKey = credentials.privateKey +address = web3.toChecksumAddress(credentials.address) + +IP = credentials.IP + +# global thread and ui variables +window = None +app = None +node_thread = None +ws_thread = None + + +class State(Enum): + disconnected = 0 + connected_P = 1 + connected_S = 2 + initialized_P = 3 + initialized_S = 4 + active_P = 5 + active_S = 6 + closed = 7 + + +# Main window class +class MainWindow(QMainWindow): + def __init__(self, parent=None): + super(MainWindow, self).__init__(parent) + global ws_thread + # load ui file + self.ui = Ui_MainWindow() + self.ui.setupUi(self) + + # connect button handlers + self.ui.closeButton.clicked.connect(self.close) + self.ui.startButton.clicked.connect(self.connectWS) + + # input list scroller + for i in range(2): + self.ui.hourList.addItem("") + self.ui.minuteList.addItem("") + + for i in range(24): + self.ui.hourList.addItem(str(i)) + + for i in range(60): + self.ui.minuteList.addItem(str(i)) + + for i in range(2): + self.ui.hourList.addItem("") + self.ui.minuteList.addItem("") + + # set list selection handler + self.ui.hourList.setCurrentRow(2) + self.ui.minuteList.setCurrentRow(2) + QObject.connect(self.ui.hourList.verticalScrollBar(), + SIGNAL('valueChanged(int)'), self, SLOT('updateHourList(int)')) + QObject.connect(self.ui.minuteList.verticalScrollBar(), + SIGNAL('valueChanged(int)'), self, SLOT('updateMinuteList(int)')) + + # TODO: + # scroller aufsetzen + # properties fuer einzelne Elemente setzen (style, clickbarkeit) + # beide gleiches aussehen, ob angeklickt oder nicht + + # self.scrollerProperties = QScrollerProperties() + # # self.scrollerProperties.setScrollMetric( + # # QScrollerProperties.DragVelocitySmoothingFactor, 0.6) + # # self.scrollerProperties.setScrollMetric(QScrollerProperties.MinimumVelocity, 0.0) + # # self.scrollerProperties.setScrollMetric(QScrollerProperties.MaximumVelocity, 0.2) + # # self.scrollerProperties.setScrollMetric( + # # QScrollerProperties.AcceleratingFlickMaximumTime, 0.1) + # # self.scrollerProperties.setScrollMetric( + # # QScrollerProperties.AcceleratingFlickSpeedupFactor, 1.2) + # # self.scrollerProperties.setScrollMetric(QScrollerProperties.SnapPositionRatio, 0.2) + # # self.scrollerProperties.setScrollMetric( + # # QScrollerProperties.MaximumClickThroughVelocity, 1) + # # self.scrollerProperties.setScrollMetric(QScrollerProperties.DragStartDistance, 0.001) + # # self.scrollerProperties.setScrollMetric(QScrollerProperties.MousePressEventDelay, 0.5) + + # self.scroller = QScroller.scroller(self.ui.hourList.viewport()) + # self.scroller.setScrollerProperties(self.scrollerProperties) + # self.scroller.grabGesture( + # self.ui.hourList.viewport(), QScroller.LeftMouseButtonGesture) + + self.ui.selectButton.clicked.connect(self.getMinutes) + + def updateHourList(self, position): + if position == 1: + self.ui.hourLabel.setText("hour") + else: + self.ui.hourLabel.setText("hours") + self.ui.hourList.setCurrentRow(position+2) + + def updateMinuteList(self, position): + if position == 1: + self.ui.minuteLabel.setText("minute") + else: + self.ui.minuteLabel.setText("minutes") + self.ui.minuteList.setCurrentRow(position+2) + + def getMinutes(self): + hours = self.ui.hourList.currentRow() - 2 + minutes = self.ui.minuteList.currentRow() - 2 + print("hrs: " + str(hours) + " mins: " + str(minutes)) + + def closeEvent(self, event): + global node_thread, ws_thread + # cleanup and end threads + node_thread.threadActive = False + node_thread.wait() + ws_thread.connectionActive = False + ws_thread.wait() + # GPIO.cleanup() + event.accept() # let the window close + + def connectWS(self): + global ws_thread + # start websocket + # ws_thread = WSConnection() + # ws_thread.start() + + +# ethereum node functionality +class Node(QThread): + def __init__(self, parent=None): + super(Node, self).__init__(parent) + global window + self.threadActive = False + + if web3.isConnected(): + self.threadActive = True + else: + window.ui.nodeInfoLabel.setText("Not connected to Node") + + def run(self): + global window + i = 0 + while self.threadActive: + i += 1 + # check if node is up to date once per second + syncing = web3.eth.syncing + if syncing is False: + blockNumber = web3.eth.blockNumber + # TODO remove str(i) + window.ui.nodeInfoLabel.setText( + "Blocknumber: " + str(blockNumber) + str(i) + ) + + else: + window.ui.nodeInfoLabel.setText( + "Syncing: " + str(syncing.currentBlock) + + "/" + str(syncing.highestBlock) + str(i) + ) + + QThread().sleep(1) + + +# websocket thread +class WSConnection(QThread): + def __init__(self, parent=None): + super(WSConnection, self).__init__(parent) + global window + + self.connectionActive = False + + def run(self): + # start websocket handler + window.ui.startButton.setVisible(False) + self.loop = asyncio.new_event_loop() + asyncio.set_event_loop(self.loop) + self.loop.run_until_complete(self.wsConnection()) + + # disconnect from websocket and display message to user + def disconnect(self, err_msg): + global window + self.connectionActive = False + window.ui.startButton.setVisible(True) + window.ui.infoLabel.setText(err_msg) + + # Websocket handler + async def wsConnection(self): + global window + + self.paymentState = State.disconnected + + # connect to socket + window.ui.infoLabel.setText('Connecting...') + # deactivate close button during connection + window.ui.closeButton.setVisible(False) + try: + # wait until connected to websocket + websocket = await websockets.connect(IP) + except: + # if connection times out close thread + window.ui.startButton.setVisible(True) + window.ui.infoLabel.setText('Failed to connect to Smart Socket') + window.ui.closeButton.setVisible(True) + self.terminate() + return + + # connection successful + self.connectionActive = True + window.ui.closeButton.setVisible(True) + window.ui.infoLabel.setText('Connected to Smart Socket') + self.paymentState = State.connected_P + + while self.connectionActive: + + if self.paymentState != State.disconnected: + # execute code according to current state + if self.paymentState == State.connected_P: + await websocket.send(json.dumps({"id": self.paymentState.value, "address": address})) + self.paymentState = State.connected_S + + elif self.paymentState == State.initialized_P: + window.ui.infoLabel.setText( + 'Fetching data from Smart Contract' + ) + # fetch data from smart contract + self.pricePerSecond = self.contract.functions.pricePerSecond().call() + self.nonce = self.contract.functions.customerNonces( + address).call() + + ownerTmp = self.contract.functions.owner().call() + + # verify contract ownership + window.ui.infoLabel.setText( + 'Verifying data with Smart Contract' + ) + if self.owner != ownerTmp: + self.paymentState = State.disconnected + else: + print('verified') + self.paymentState = State.initialized_S + + else: + # disconnect from websocket if state is disconnected + self.disconnect('Websocket connection disconnected.') + + # check for new messages + message = None + try: + message = await asyncio.wait_for(websocket.recv(), timeout=0.05) + except asyncio.TimeoutError: + # no new message + pass + + # received message + if message != None: + try: + # parse JSON of message + parsedMessage = json.loads(message) + print(parsedMessage) + + # execute code according to states + if parsedMessage['id'] == State.connected_S.value: + self.contractAddr = web3.toChecksumAddress( + parsedMessage['contract'] + ) + self.owner = web3.toChecksumAddress( + parsedMessage['owner'] + ) + self.secondsPerPayment = parsedMessage['secondsPerPayment'] + # setup contract + self.contract = web3.eth.contract( + address=self.contractAddr, abi=contract_abi) + self.paymentState = State.initialized_P + + elif parsedMessage['id'] == State.initialized_S.value: + self.transactionCounter = 0 + self.transactionValue = 0 + self.paymentState = State.active_P + + elif parsedMessage['id'] == State.closed.value: + euroValue = transactionValue * etherPriceEUR / 1000000000000000000 + # TODO display transaction value + self.paymentState = State.disconnected + + except JSONDecodeError: + print('Received message could not be parsed: ' + message) + pass + + except KeyError: + print('Key of message does not exist: ' + message) + pass + + await websocket.close() + return + + +def main(): + global window + global app + global node_thread + + # start main thread + node_thread = Node() + node_thread.start() + + # start window and ui + app = QApplication(sys.argv) + window = MainWindow() + + # show ui + # window.showFullScreen() + window.show() + + sys.exit(app.exec_()) + + +if __name__ == "__main__": + main() diff --git a/plug_py/qt/Plug_python.pro b/plug_py/qt/Plug_python.pro new file mode 100644 index 0000000..c694d79 --- /dev/null +++ b/plug_py/qt/Plug_python.pro @@ -0,0 +1,40 @@ +#------------------------------------------------- +# +# Project created by QtCreator 2019-08-20T08:38:25 +# +#------------------------------------------------- + +QT += core gui + +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +TARGET = Plug_python +TEMPLATE = app + +# The following define makes your compiler emit warnings if you use +# any feature of Qt which has been marked as deprecated (the exact warnings +# depend on your compiler). Please consult the documentation of the +# deprecated API in order to know how to port your code away from it. +DEFINES += QT_DEPRECATED_WARNINGS + +# You can also make your code fail to compile if you use deprecated APIs. +# In order to do so, uncomment the following line. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +CONFIG += c++11 + +SOURCES += \ + main.cpp \ + mainwindow.cpp + +HEADERS += \ + mainwindow.h + +FORMS += \ + mainwindow.ui + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/plug_py/qt/Plug_python.pro.user b/plug_py/qt/Plug_python.pro.user new file mode 100644 index 0000000..be0ed63 --- /dev/null +++ b/plug_py/qt/Plug_python.pro.user @@ -0,0 +1,336 @@ + + + + + + EnvironmentId + {92870ea4-37a7-43bd-990a-109b15ee3aaf} + + + ProjectExplorer.Project.ActiveTarget + 0 + + + ProjectExplorer.Project.EditorSettings + + true + false + true + + Cpp + + CppGlobal + + + + QmlJS + + QmlJSGlobal + + + 2 + UTF-8 + false + 4 + false + 80 + true + true + 1 + true + false + 0 + true + true + 0 + 8 + true + 1 + true + true + true + false + + + + ProjectExplorer.Project.PluginSettings + + + true + + + + ProjectExplorer.Project.Target.0 + + Desktop Qt 5.13.0 clang 64bit + Desktop Qt 5.13.0 clang 64bit + qt.qt5.5130.clang_64_kit + 0 + 0 + 0 + + /Users/Daniel/Documents/Uni/Bachelor/Absolviert/Bachelorarbeit/git/plug_py/build-Plug_python-Desktop_Qt_5_13_0_clang_64bit-Debug + + + true + qmake + + QtProjectManager.QMakeBuildStep + true + + false + false + false + + + true + Make + + Qt4ProjectManager.MakeStep + + false + + + false + + 2 + Erstellen + + ProjectExplorer.BuildSteps.Build + + + + true + Make + + Qt4ProjectManager.MakeStep + + true + clean + + false + + 1 + Bereinigen + + ProjectExplorer.BuildSteps.Clean + + 2 + false + + Debug + Debug + Qt4ProjectManager.Qt4BuildConfiguration + 2 + true + + + /Users/Daniel/Documents/Uni/Bachelor/Absolviert/Bachelorarbeit/git/plug_py/build-Plug_python-Desktop_Qt_5_13_0_clang_64bit-Release + + + true + qmake + + QtProjectManager.QMakeBuildStep + false + + false + false + true + + + true + Make + + Qt4ProjectManager.MakeStep + + false + + + false + + 2 + Erstellen + + ProjectExplorer.BuildSteps.Build + + + + true + Make + + Qt4ProjectManager.MakeStep + + true + clean + + false + + 1 + Bereinigen + + ProjectExplorer.BuildSteps.Clean + + 2 + false + + Release + Release + Qt4ProjectManager.Qt4BuildConfiguration + 0 + true + + + /Users/Daniel/Documents/Uni/Bachelor/Absolviert/Bachelorarbeit/git/plug_py/build-Plug_python-Desktop_Qt_5_13_0_clang_64bit-Profile + + + true + qmake + + QtProjectManager.QMakeBuildStep + true + + false + true + true + + + true + Make + + Qt4ProjectManager.MakeStep + + false + + + false + + 2 + Erstellen + + ProjectExplorer.BuildSteps.Build + + + + true + Make + + Qt4ProjectManager.MakeStep + + true + clean + + false + + 1 + Bereinigen + + ProjectExplorer.BuildSteps.Clean + + 2 + false + + Profile + Profile + Qt4ProjectManager.Qt4BuildConfiguration + 0 + true + + 3 + + + 0 + Deployment + + ProjectExplorer.BuildSteps.Deploy + + 1 + Deployment-Konfiguration + + ProjectExplorer.DefaultDeployConfiguration + + 1 + + + dwarf + + cpu-cycles + + + 250 + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + Plug_python + + Qt4ProjectManager.Qt4RunConfiguration:/Users/Daniel/Documents/Uni/Bachelor/Absolviert/Bachelorarbeit/git/plug_py/qt/Plug_python.pro + + 3768 + false + true + false + true + false + false + true + + /Users/Daniel/Documents/Uni/Bachelor/Absolviert/Bachelorarbeit/git/plug_py/build-Plug_python-Desktop_Qt_5_13_0_clang_64bit-Debug/Plug_python.app/Contents/MacOS + + 1 + + + + ProjectExplorer.Project.TargetCount + 1 + + + ProjectExplorer.Project.Updater.FileVersion + 21 + + + Version + 21 + + diff --git a/plug_py/qt/main.cpp b/plug_py/qt/main.cpp new file mode 100644 index 0000000..b48f94e --- /dev/null +++ b/plug_py/qt/main.cpp @@ -0,0 +1,11 @@ +#include "mainwindow.h" +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + MainWindow w; + w.show(); + + return a.exec(); +} diff --git a/plug_py/qt/mainwindow.cpp b/plug_py/qt/mainwindow.cpp new file mode 100644 index 0000000..49d64fc --- /dev/null +++ b/plug_py/qt/mainwindow.cpp @@ -0,0 +1,14 @@ +#include "mainwindow.h" +#include "ui_mainwindow.h" + +MainWindow::MainWindow(QWidget *parent) : + QMainWindow(parent), + ui(new Ui::MainWindow) +{ + ui->setupUi(this); +} + +MainWindow::~MainWindow() +{ + delete ui; +} diff --git a/plug_py/qt/mainwindow.h b/plug_py/qt/mainwindow.h new file mode 100644 index 0000000..9353441 --- /dev/null +++ b/plug_py/qt/mainwindow.h @@ -0,0 +1,22 @@ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include + +namespace Ui { +class MainWindow; +} + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + explicit MainWindow(QWidget *parent = nullptr); + ~MainWindow(); + +private: + Ui::MainWindow *ui; +}; + +#endif // MAINWINDOW_H diff --git a/plug_py/qt/mainwindow.ui b/plug_py/qt/mainwindow.ui new file mode 100644 index 0000000..3bc552c --- /dev/null +++ b/plug_py/qt/mainwindow.ui @@ -0,0 +1,259 @@ + + + MainWindow + + + + 0 + 0 + 800 + 480 + + + + MainWindow + + + background-color: rgb(50, 50, 50); + + + + + + 440 + 450 + 351 + 20 + + + + color: white + + + Currently not connected to node + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + 720 + 10 + 64 + 64 + + + + color: transparent; border: none + + + X + + + + + true + + + + 185 + 10 + 430 + 50 + + + + Qt::LeftToRight + + + font-size:30pt; font-style:italic; color:white; + + + Blockchain-Based Smart Outlet + + + Qt::AlignCenter + + + + + + 85 + 140 + 630 + 40 + + + + color:white; font-size:20px + + + + + + Qt::AlignCenter + + + + + + 300 + 190 + 200 + 100 + + + + color: white; background-color: rgba(0,255, 0, 0.75); border: none; font-size: 24px; border-radius:5px + + + Connect to +Smart Socket + + + + + + 340 + 320 + 120 + 40 + + + + color:black; background-color:white; border-radius: 4px + + + Select + + + + + + 480 + 233 + 60 + 20 + + + + + 16 + 50 + false + + + + color:white + + + minutes + + + + + + 260 + 190 + 75 + 108 + + + + + 16 + 75 + true + + + + color:white; + + + Qt::ScrollBarAlwaysOff + + + Qt::ScrollBarAlwaysOff + + + false + + + false + + + QAbstractItemView::ScrollPerItem + + + -1 + + + + + + 400 + 190 + 75 + 108 + + + + + 16 + 75 + true + + + + color:white; + + + Qt::ScrollBarAlwaysOff + + + Qt::ScrollBarAlwaysOff + + + false + + + false + + + QAbstractItemView::ScrollPerItem + + + -1 + + + + + + 340 + 233 + 60 + 20 + + + + + 16 + 50 + false + + + + color:white + + + hours + + + + + + + + diff --git a/plug_py/ui_mainwindow.py b/plug_py/ui_mainwindow.py new file mode 100644 index 0000000..79dd768 --- /dev/null +++ b/plug_py/ui_mainwindow.py @@ -0,0 +1,113 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'qt/mainwindow.ui', +# licensing of 'qt/mainwindow.ui' applies. +# +# Created: Sun Aug 25 02:48:08 2019 +# by: pyside2-uic running on PySide2 5.13.0 +# +# WARNING! All changes made in this file will be lost! + +from PySide2 import QtCore, QtGui, QtWidgets + +class Ui_MainWindow(object): + def setupUi(self, MainWindow): + MainWindow.setObjectName("MainWindow") + MainWindow.resize(800, 480) + MainWindow.setStyleSheet("background-color: rgb(50, 50, 50);") + self.centralWidget = QtWidgets.QWidget(MainWindow) + self.centralWidget.setObjectName("centralWidget") + self.nodeInfoLabel = QtWidgets.QLabel(self.centralWidget) + self.nodeInfoLabel.setGeometry(QtCore.QRect(440, 450, 351, 20)) + self.nodeInfoLabel.setStyleSheet("color: white") + self.nodeInfoLabel.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) + self.nodeInfoLabel.setObjectName("nodeInfoLabel") + self.closeButton = QtWidgets.QPushButton(self.centralWidget) + self.closeButton.setGeometry(QtCore.QRect(720, 10, 64, 64)) + self.closeButton.setStyleSheet("color: transparent; border: none") + self.closeButton.setObjectName("closeButton") + self.titleLabel = QtWidgets.QLabel(self.centralWidget) + self.titleLabel.setEnabled(True) + self.titleLabel.setGeometry(QtCore.QRect(185, 10, 430, 50)) + self.titleLabel.setLayoutDirection(QtCore.Qt.LeftToRight) + self.titleLabel.setStyleSheet("font-size:30pt; font-style:italic; color:white;") + self.titleLabel.setAlignment(QtCore.Qt.AlignCenter) + self.titleLabel.setObjectName("titleLabel") + self.infoLabel = QtWidgets.QLabel(self.centralWidget) + self.infoLabel.setGeometry(QtCore.QRect(85, 140, 630, 40)) + self.infoLabel.setStyleSheet("color:white; font-size:20px") + self.infoLabel.setText("") + self.infoLabel.setAlignment(QtCore.Qt.AlignCenter) + self.infoLabel.setObjectName("infoLabel") + self.startButton = QtWidgets.QPushButton(self.centralWidget) + self.startButton.setGeometry(QtCore.QRect(300, 190, 200, 100)) + self.startButton.setStyleSheet("color: white; background-color: rgba(0,255, 0, 0.75); border: none; font-size: 24px; border-radius:5px") + self.startButton.setObjectName("startButton") + self.selectButton = QtWidgets.QPushButton(self.centralWidget) + self.selectButton.setGeometry(QtCore.QRect(340, 320, 120, 40)) + self.selectButton.setStyleSheet("color:black; background-color:white; border-radius: 4px") + self.selectButton.setObjectName("selectButton") + self.minuteLabel = QtWidgets.QLabel(self.centralWidget) + self.minuteLabel.setGeometry(QtCore.QRect(480, 233, 60, 20)) + font = QtGui.QFont() + font.setPointSize(16) + font.setWeight(50) + font.setBold(False) + self.minuteLabel.setFont(font) + self.minuteLabel.setStyleSheet("color:white") + self.minuteLabel.setObjectName("minuteLabel") + self.hourList = QtWidgets.QListWidget(self.centralWidget) + self.hourList.setGeometry(QtCore.QRect(260, 190, 75, 108)) + font = QtGui.QFont() + font.setPointSize(16) + font.setWeight(75) + font.setBold(True) + self.hourList.setFont(font) + self.hourList.setStyleSheet("color:white;") + self.hourList.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) + self.hourList.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) + self.hourList.setDragEnabled(False) + self.hourList.setAlternatingRowColors(False) + self.hourList.setVerticalScrollMode(QtWidgets.QAbstractItemView.ScrollPerItem) + self.hourList.setObjectName("hourList") + self.minuteList = QtWidgets.QListWidget(self.centralWidget) + self.minuteList.setGeometry(QtCore.QRect(400, 190, 75, 108)) + font = QtGui.QFont() + font.setPointSize(16) + font.setWeight(75) + font.setBold(True) + self.minuteList.setFont(font) + self.minuteList.setStyleSheet("color:white;") + self.minuteList.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) + self.minuteList.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) + self.minuteList.setDragEnabled(False) + self.minuteList.setAlternatingRowColors(False) + self.minuteList.setVerticalScrollMode(QtWidgets.QAbstractItemView.ScrollPerItem) + self.minuteList.setObjectName("minuteList") + self.hourLabel = QtWidgets.QLabel(self.centralWidget) + self.hourLabel.setGeometry(QtCore.QRect(340, 233, 60, 20)) + font = QtGui.QFont() + font.setPointSize(16) + font.setWeight(50) + font.setBold(False) + self.hourLabel.setFont(font) + self.hourLabel.setStyleSheet("color:white") + self.hourLabel.setObjectName("hourLabel") + MainWindow.setCentralWidget(self.centralWidget) + + self.retranslateUi(MainWindow) + self.hourList.setCurrentRow(-1) + self.minuteList.setCurrentRow(-1) + QtCore.QMetaObject.connectSlotsByName(MainWindow) + + def retranslateUi(self, MainWindow): + MainWindow.setWindowTitle(QtWidgets.QApplication.translate("MainWindow", "MainWindow", None, -1)) + self.nodeInfoLabel.setText(QtWidgets.QApplication.translate("MainWindow", "Currently not connected to node", None, -1)) + self.closeButton.setText(QtWidgets.QApplication.translate("MainWindow", "X", None, -1)) + self.titleLabel.setText(QtWidgets.QApplication.translate("MainWindow", "Blockchain-Based Smart Outlet", None, -1)) + self.startButton.setText(QtWidgets.QApplication.translate("MainWindow", "Connect to\n" +"Smart Socket", None, -1)) + self.selectButton.setText(QtWidgets.QApplication.translate("MainWindow", "Select", None, -1)) + self.minuteLabel.setText(QtWidgets.QApplication.translate("MainWindow", "minutes", None, -1)) + self.hourLabel.setText(QtWidgets.QApplication.translate("MainWindow", "hours", None, -1)) +