From 6e6ebc60371c09b08c2dbd6a6411d6f693ff8a4e Mon Sep 17 00:00:00 2001 From: yann300 Date: Mon, 8 Jun 2015 13:42:39 +0200 Subject: [PATCH] ScenarioExecution.qml ux design --- mix/qml.qrc | 1 + mix/qml/Block.qml | 169 +++++++++------ mix/qml/BlockChain.qml | 334 +++++++++++++++++------------ mix/qml/ScenarioButton.qml | 62 ++++++ mix/qml/ScenarioExecution.qml | 7 +- mix/qml/ScenarioLoader.qml | 27 ++- mix/qml/StateListModel.qml | 5 +- mix/qml/img/duplicateIcon.png | Bin 0 -> 1020 bytes mix/qml/img/duplicateIcon@2x.png | Bin 0 -> 2326 bytes mix/qml/img/newIcon.png | Bin 0 -> 801 bytes mix/qml/img/newIcon@2x.png | Bin 0 -> 1768 bytes mix/qml/img/recycle-discard.png | Bin 0 -> 723 bytes mix/qml/img/recycle-discard@2x.png | Bin 0 -> 1568 bytes mix/qml/img/recycle-icon.png | Bin 0 -> 697 bytes mix/qml/img/recycle-icon@2x.png | Bin 0 -> 1435 bytes mix/qml/img/recycle-keep.png | Bin 0 -> 904 bytes mix/qml/img/recycle-keep@2x.png | Bin 0 -> 2141 bytes mix/qml/img/restoreIcon.png | Bin 0 -> 1124 bytes mix/qml/img/restoreIcon@2x.png | Bin 0 -> 2447 bytes mix/qml/img/saveIcon.png | Bin 0 -> 1068 bytes mix/qml/img/saveIcon@2x.png | Bin 0 -> 2359 bytes mix/res.qrc | 12 ++ 22 files changed, 409 insertions(+), 208 deletions(-) create mode 100644 mix/qml/ScenarioButton.qml create mode 100644 mix/qml/img/duplicateIcon.png create mode 100644 mix/qml/img/duplicateIcon@2x.png create mode 100644 mix/qml/img/newIcon.png create mode 100644 mix/qml/img/newIcon@2x.png create mode 100644 mix/qml/img/recycle-discard.png create mode 100644 mix/qml/img/recycle-discard@2x.png create mode 100644 mix/qml/img/recycle-icon.png create mode 100644 mix/qml/img/recycle-icon@2x.png create mode 100644 mix/qml/img/recycle-keep.png create mode 100644 mix/qml/img/recycle-keep@2x.png create mode 100644 mix/qml/img/restoreIcon.png create mode 100644 mix/qml/img/restoreIcon@2x.png create mode 100644 mix/qml/img/saveIcon.png create mode 100644 mix/qml/img/saveIcon@2x.png diff --git a/mix/qml.qrc b/mix/qml.qrc index 0227b4efd..16bb01b83 100644 --- a/mix/qml.qrc +++ b/mix/qml.qrc @@ -68,5 +68,6 @@ qml/BlockChain.qml qml/ScenarioExecution.qml qml/ScenarioLoader.qml + qml/ScenarioButton.qml diff --git a/mix/qml/Block.qml b/mix/qml/Block.qml index c3ce7865a..d3775ea5c 100644 --- a/mix/qml/Block.qml +++ b/mix/qml/Block.qml @@ -10,25 +10,40 @@ import "." ColumnLayout { + id: root property variant transactions property string status property int number - Rectangle - { - width: parent.width - height: 50 - anchors.left: parent.left - anchors.leftMargin: statusWidth - Label { - text: - { - if (status === "mined") - return qsTr("BLOCK") + " " + number - else - return qsTr("BLOCK") + " pending" - } + property int blockWidth: Layout.preferredWidth - statusWidth - horizontalMargin + property int horizontalMargin: 10 + property int trHeight: 30 + spacing: 0 + RowLayout + { + Layout.preferredHeight: trHeight + Layout.preferredWidth: blockWidth + id: rowHeader + Rectangle + { + color: "#DEDCDC" + Layout.preferredWidth: blockWidth + Layout.preferredHeight: trHeight + radius: 4 anchors.left: parent.left + anchors.leftMargin: statusWidth + 5 + Label { + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + anchors.leftMargin: horizontalMargin + text: + { + if (status === "mined") + return qsTr("BLOCK") + " " + number + else + return qsTr("BLOCK") + " pending" + } + } } } @@ -36,57 +51,80 @@ ColumnLayout { id: transactionRepeater model: transactions - Row + + RowLayout { - height: 50 + Layout.preferredHeight: trHeight Rectangle { id: trSaveStatus + Layout.preferredWidth: statusWidth + Layout.preferredHeight: trHeight color: "transparent" - CheckBox + property bool saveStatus + + Image { + id: saveStatusImage + source: "qrc:/qml/img/recycle-discard@2x.png" + width: statusWidth + fillMode: Image.PreserveAspectFit + anchors.verticalCenter: parent.verticalCenter + anchors.horizontalCenter: parent.horizontalCenter + } + + Component.onCompleted: { - id: saveStatus - checked: { - if (index >= 0) - return transactions.get(index).saveStatus - else - return true - } - onCheckedChanged: + if (index >= 0) + saveStatus = transactions.get(index).saveStatus + } + + onSaveStatusChanged: + { + if (saveStatus) + saveStatusImage.source = "qrc:/qml/img/recycle-keep@2x.png" + else + saveStatusImage.source = "qrc:/qml/img/recycle-discard@2x.png" + + if (index >= 0) + transactions.get(index).saveStatus = saveStatus + } + + MouseArea { + id: statusMouseArea + anchors.fill: parent + onClicked: { - if (index >= 0) - transactions.get(index).saveStatus = checked + parent.saveStatus = !parent.saveStatus } } } Rectangle { - width: parent.width - height: 50 - color: "#cccccc" - radius: 4 - Row + Layout.preferredWidth: blockWidth + Layout.preferredHeight: parent.height + color: "#DEDCDC" + RowLayout { - Label - { - id: status - width: statusWidth - } - Label + anchors.verticalCenter: parent.verticalCenter + spacing: cellSpacing + Text { id: hash - width: fromWidth + anchors.left: parent.left + anchors.leftMargin: horizontalMargin + Layout.preferredWidth: fromWidth + elide: Text.ElideRight + maximumLineCount: 1 text: { if (index >= 0) return transactions.get(index).sender else return "" } - - clip: true } - Label + + Text { id: func text: { @@ -95,9 +133,9 @@ ColumnLayout else return "" } - - width: toWidth - clip: true + elide: Text.ElideRight + maximumLineCount: 1 + Layout.preferredWidth: toWidth } function userFrienldyToken(value) @@ -108,43 +146,52 @@ ColumnLayout return value } - Label + Text { id: returnValue - width: valueWidth + elide: Text.ElideRight + maximumLineCount: 1 + Layout.preferredWidth: valueWidth text: { if (index >= 0 && transactions.get(index).returned) return transactions.get(index).returned else return "" } - clip: true } - Label + Rectangle { - id: logs + Layout.preferredWidth: logsWidth + Layout.preferredHeight: trHeight - 10 width: logsWidth - text: { - if (index >= 0 && transactions.get(index).logs) - { - for (var k in transactions.get(index).logs) + color: "transparent" + Text + { + id: logs + anchors.left: parent.left + anchors.leftMargin: 10 + text: { + if (index >= 0 && transactions.get(index).logs && transactions.get(index).logs.count) { - console.log("_________________________") - console.log(JSON.stringify(transactions.get(index).logs[k])) - console.log("_________________________") + for (var k = 0; k < transactions.get(index).logs.count; k++) + { + /*console.log("_________________________") + console.log(JSON.stringify(transactions.get(index).logs[k])) + console.log("_________________________")*/ + } + return transactions.get(index).logs.count } - return transactions.get(index).logs.length + else + return "" } - else - return 0 } } Button { id: debug - width: debugActionWidth + Layout.preferredWidth: debugActionWidth text: "debug" onClicked: { diff --git a/mix/qml/BlockChain.qml b/mix/qml/BlockChain.qml index 6098ec035..2fc78b0b1 100644 --- a/mix/qml/BlockChain.qml +++ b/mix/qml/BlockChain.qml @@ -11,91 +11,126 @@ import "js/TransactionHelper.js" as TransactionHelper import "js/QEtherHelper.js" as QEtherHelper import "." -Column { +ColumnLayout { id: blockChainPanel property variant model - spacing: 5 + spacing: 0 + property int previousWidth + onWidthChanged: + { + + if (width <= 630 || previousWidth <= 630) + { + fromWidth = 100 + toWidth = 100 + valueWidth = 200 + } + else + { + var diff = (width - previousWidth) / 3; + fromWidth = fromWidth + diff < 100 ? 100 : fromWidth + diff + toWidth = toWidth + diff < 100 ? 100 : toWidth + diff + valueWidth = valueWidth + diff < 200 ? 200 : valueWidth + diff + } + previousWidth = width + } function load(scenario) { - if (!scenario) return; model = scenario blockModel.clear() for (var b in model.blocks) blockModel.append(model.blocks[b]) + previousWidth = width } - property int statusWidth: 50 + property int statusWidth: 30 property int fromWidth: 100 - property int toWidth: 250 - property int valueWidth: 50 + property int toWidth: 100 + property int valueWidth: 200 property int logsWidth: 50 property int debugActionWidth: 50 + property int horizontalMargin: 10 + property int cellSpacing: 10 - Row + RowLayout { id: header - width: parent.width - Label - { - text: "Status" - width: statusWidth + spacing: 0 + Layout.preferredHeight: 25 + Image { + id: debugImage + source: "qrc:/qml/img/recycle-icon@2x.png" + Layout.preferredWidth: statusWidth + Layout.preferredHeight: 25 + fillMode: Image.PreserveAspectFit } - Label + Rectangle { - text: "From" - width: fromWidth + Layout.preferredWidth: fromWidth + cellSpacing + Label + { + anchors.verticalCenter: parent.verticalCenter + text: "From" + anchors.left: parent.left + anchors.leftMargin: horizontalMargin + 5 + } } Label { text: "To" - width: toWidth + Layout.preferredWidth: toWidth + cellSpacing } Label { text: "Value" - width: valueWidth + Layout.preferredWidth: valueWidth + cellSpacing } Label { text: "Logs" - width: logsWidth + Layout.preferredWidth: logsWidth + cellSpacing } Label { text: "Action" - width: debugActionWidth + Layout.preferredWidth: debugActionWidth } } Rectangle { - width: parent.width - height: 500 + Layout.preferredHeight: 500 + Layout.preferredWidth: parent.width + //height: 500 border.color: "#cccccc" border.width: 2 color: "white" ScrollView { - width: parent.width - height: parent.height + id: blockChainScrollView + anchors.fill: parent + anchors.topMargin: 10 ColumnLayout { + id: blockChainLayout + width: parent.width + spacing: 10 Repeater // List of blocks { id: blockChainRepeater - width: parent.width model: blockModel Block { - height: + Layout.preferredWidth: blockChainScrollView.width + Layout.preferredHeight: { if (index >= 0) - return 50 + 50 * blockModel.get(index).transactions.length + return 30 + 30 * blockModel.get(index).transactions.count else - return 0 + return 50 } transactions: @@ -143,8 +178,6 @@ Column { function removeTransaction(blockIndex, trIndex) { - console.log(blockIndex) - console.log(trIndex) blockModel.get(blockIndex).transactions.remove(trIndex) } @@ -160,139 +193,174 @@ Column { function getTransaction(block, tr) { - return blockModel.get(block - 1).transactions.get(tr) + return blockModel.get(block).transactions.get(tr) + } + + function setTransaction(blockIndex, trIndex, tr) + { + blockModel.get(blockIndex).transactions.set(trIndex, tr) + } + + function setTransactionProperty(blockIndex, trIndex, propertyName, value) + { + blockModel.get(blockIndex).transactions.set(trIndex, { propertyName: value }) } } - RowLayout + Rectangle { - width: parent.width - Button { - id: rebuild - text: qsTr("Rebuild") - onClicked: - { - for (var j = 0; j < model.blocks.length; j++) + Layout.preferredWidth: parent.width + RowLayout + { + width: parent.width + anchors.top: parent.top + anchors.topMargin: 10 + ScenarioButton { + id: rebuild + text: qsTr("Rebuild") + onClicked: { - for (var k = 0; k < model.blocks[j].transactions.length; k++) + for (var j = 0; j < model.blocks.length; j++) { - if (!blockModel.get(j).transactions.get(k).saveStatus) + for (var k = 0; k < model.blocks[j].transactions.length; k++) { - model.blocks[j].transactions.splice(k, 1) - blockModel.removeTransaction(j, k) - if (model.blocks[j].transactions.length === 0) + if (!blockModel.get(j).transactions.get(k).saveStatus) { - model.blocks[j].splice(j, 1); - blockModel.removeBlock(j); + model.blocks[j].transactions.splice(k, 1) + blockModel.removeTransaction(j, k) + if (model.blocks[j].transactions.length === 0) + { + model.blocks.splice(j, 1); + blockModel.removeBlock(j); + } } } } + clientModel.setupScenario(model); } - clientModel.setupScenario(model); - } - } - Button { - id: addTransaction - text: qsTr("Add Transaction") - onClicked: - { - var lastBlock = model.blocks[model.blocks.length - 1]; - if (lastBlock.status === "mined") - model.blocks.push(projectModel.stateListModel.createEmptyBlock()); - var item = TransactionHelper.defaultTransaction() - transactionDialog.stateAccounts = model.accounts - transactionDialog.open(model.blocks[model.blocks.length - 1].transactions.length, model.blocks.length - 1, item) + Layout.preferredWidth: 100 + Layout.preferredHeight: 30 + buttonShortcut: "" + sourceImg: "qrc:/qml/img/recycle-icon@2x.png" } - } - Button { - id: addBlockBtn - text: qsTr("Add Block") - onClicked: - { - var lastBlock = model.blocks[model.blocks.length - 1] - if (lastBlock.status === "pending") - clientModel.mine() - else - addNewBlock() - } - - function addNewBlock() - { - var block = projectModel.stateListModel.createEmptyBlock() - model.blocks.push(block) - blockModel.appendBlock(block) + ScenarioButton { + id: addTransaction + text: qsTr("Add Transaction") + onClicked: + { + var lastBlock = model.blocks[model.blocks.length - 1]; + if (lastBlock.status === "mined") + model.blocks.push(projectModel.stateListModel.createEmptyBlock()); + var item = TransactionHelper.defaultTransaction() + transactionDialog.stateAccounts = model.accounts + transactionDialog.open(model.blocks[model.blocks.length - 1].transactions.length, model.blocks.length - 1, item) + } + Layout.preferredWidth: 100 + Layout.preferredHeight: 30 + buttonShortcut: "" + sourceImg: "qrc:/qml/img/recycle-icon@2x.png" } - } - Connections - { - target: clientModel - onNewBlock: - { - if (!clientModel.running) + ScenarioButton { + id: addBlockBtn + text: qsTr("Add Block") + onClicked: { var lastBlock = model.blocks[model.blocks.length - 1] - lastBlock.status = "mined" - lastBlock.number = model.blocks.length - var lastB = blockModel.get(model.blocks.length - 1) - lastB.status = "mined" - lastB.number = model.blocks.length - addBlockBtn.addNewBlock() + if (lastBlock.status === "pending") + clientModel.mine() + else + addNewBlock() } + + function addNewBlock() + { + var block = projectModel.stateListModel.createEmptyBlock() + model.blocks.push(block) + blockModel.appendBlock(block) + } + Layout.preferredWidth: 100 + Layout.preferredHeight: 30 + buttonShortcut: "" + sourceImg: "qrc:/qml/img/recycle-icon@2x.png" } - onStateCleared: - { - } - onNewRecord: + + Connections { - var blockIndex = _r.transactionIndex.split(":")[0] - var trIndex = _r.transactionIndex.split(":")[1] - if (parseInt(blockIndex) <= model.blocks.length) + target: clientModel + onNewBlock: { - var item = model.blocks[parseInt(blockIndex) - 1]; - if (parseInt(trIndex) <= item.transactions.length) + if (!clientModel.running) { - var tr = item.transactions[parseInt(trIndex)]; - tr.returned = _r.returned; - blockModel.getTransaction(blockIndex, trIndex).returned = _r.returned; - tr.recordIndex = _r.recordIndex; - blockModel.getTransaction(blockIndex, trIndex).recordIndex = _r.recordIndex; - tr.logs = _r.logs; - blockModel.getTransaction(blockIndex, trIndex).logs = _r.logs; - return; + var lastBlock = model.blocks[model.blocks.length - 1] + lastBlock.status = "mined" + lastBlock.number = model.blocks.length + var lastB = blockModel.get(model.blocks.length - 1) + lastB.status = "mined" + lastB.number = model.blocks.length + addBlockBtn.addNewBlock() } } + onStateCleared: + { + } + onNewRecord: + { + var blockIndex = parseInt(_r.transactionIndex.split(":")[0]) - 1 + var trIndex = parseInt(_r.transactionIndex.split(":")[1]) + if (blockIndex <= model.blocks.length) + { + var item = model.blocks[blockIndex] + if (trIndex <= item.transactions.length) + { + var tr = item.transactions[trIndex] + tr.returned = _r.returned + tr.recordIndex = _r.recordIndex + tr.logs = _r.logs + var trModel = blockModel.getTransaction(blockIndex, trIndex) + trModel.returned = _r.returned + trModel.recordIndex = _r.recordIndex + trModel.logs = _r.logs + blockModel.setTransaction(blockIndex, trIndex, trModel) + return; + } + } - // tr is not in the list. coming from JavaScript - var itemTr = TransactionHelper.defaultTransaction() - itemTr.functionId = _r.function - itemTr.contractId = _r.contract - itemTr.gasAuto = true - itemTr.parameters = _r.parameters - itemTr.isContractCreation = itemTr.functionId === itemTr.contractId - itemTr.label = _r.label - itemTr.isFunctionCall = itemTr.functionId !== "" - itemTr.returned = _r.returned - itemTr.value = QEtherHelper.createEther(_r.value, QEther.Wei) - itemTr.sender = _r.sender - itemTr.recordIndex = _r.recordIndex - itemTr.logs = _r.logs - - model.blocks[model.blocks.length - 1].transactions.push(itemTr) - blockModel.appendTransaction(itemTr) - } - onMiningComplete: - { + // tr is not in the list. coming from JavaScript + var itemTr = TransactionHelper.defaultTransaction() + itemTr.saveStatus = false + itemTr.functionId = _r.function + itemTr.contractId = _r.contract + itemTr.gasAuto = true + itemTr.parameters = _r.parameters + itemTr.isContractCreation = itemTr.functionId === itemTr.contractId + itemTr.label = _r.label + itemTr.isFunctionCall = itemTr.functionId !== "" + itemTr.returned = _r.returned + itemTr.value = QEtherHelper.createEther(_r.value, QEther.Wei) + itemTr.sender = _r.sender + itemTr.recordIndex = _r.recordIndex + itemTr.logs = _r.logs + model.blocks[model.blocks.length - 1].transactions.push(itemTr) + blockModel.appendTransaction(itemTr) + } + onMiningComplete: + { + } } - } - Button { - id: newAccount - text: qsTr("New Account") - onClicked: { - model.accounts.push(projectModel.stateListModel.newAccount("1000000", QEther.Ether)) + ScenarioButton { + id: newAccount + text: qsTr("New Account") + onClicked: { + model.accounts.push(projectModel.stateListModel.newAccount("1000000", QEther.Ether)) + } + Layout.preferredWidth: 100 + Layout.preferredHeight: 30 + buttonShortcut: "" + sourceImg: "qrc:/qml/img/recycle-icon@2x.png" } } } diff --git a/mix/qml/ScenarioButton.qml b/mix/qml/ScenarioButton.qml new file mode 100644 index 000000000..e8884cc2e --- /dev/null +++ b/mix/qml/ScenarioButton.qml @@ -0,0 +1,62 @@ +import QtQuick 2.2 +import QtQuick.Controls 1.1 +import QtQuick.Layouts 1.0 +import QtQuick.Controls.Styles 1.1 + +Rectangle { + id: buttonActionContainer + property string text + property string buttonShortcut + property string sourceImg + signal clicked + + Rectangle { + id: contentRectangle + anchors.fill: parent + border.color: "#cccccc" + border.width: 1 + radius: 4 + Image { + id: debugImage + anchors { + centerIn: parent + bottomMargin: debugImg.pressed ? 0 : 1; + topMargin: debugImg.pressed ? 1 : 0; + } + source: sourceImg + fillMode: Image.PreserveAspectFit + height: 30 + } + + Button { + anchors.fill: parent + id: debugImg + action: buttonAction + style: ButtonStyle { + background: Rectangle { + color: "transparent" + } + } + } + + Action { + id: buttonAction + shortcut: buttonShortcut + onTriggered: { + buttonActionContainer.clicked(); + } + } + } + + Rectangle + { + anchors.top: contentRectangle.bottom + anchors.topMargin: 15 + width: parent.width + Text + { + text: buttonActionContainer.text + anchors.centerIn: parent + } + } +} diff --git a/mix/qml/ScenarioExecution.qml b/mix/qml/ScenarioExecution.qml index 5fcbfab3e..d02e7d3f8 100644 --- a/mix/qml/ScenarioExecution.qml +++ b/mix/qml/ScenarioExecution.qml @@ -9,9 +9,7 @@ import "js/ErrorLocationFormater.js" as ErrorLocationFormater import "." Rectangle { - - border.color: "red" - border.width: 1 + color: "#ededed" Connections { @@ -26,9 +24,10 @@ Rectangle { { anchors.margins: 10 anchors.fill: parent - spacing: 5 + spacing: 10 ScenarioLoader { + height: 70 width: parent.width id: loader } diff --git a/mix/qml/ScenarioLoader.qml b/mix/qml/ScenarioLoader.qml index 0b703c860..b89c1222b 100644 --- a/mix/qml/ScenarioLoader.qml +++ b/mix/qml/ScenarioLoader.qml @@ -37,32 +37,39 @@ RowLayout loaded(state) } } - Button - { + + ScenarioButton { id: restoreScenario - text: qsTr("Restore") + Layout.preferredWidth: 100 + Layout.preferredHeight: 30 + buttonShortcut: "" + sourceImg: "qrc:/qml/img/restoreIcon@2x.png" onClicked: { restore() } - + text: qsTr("Restore") function restore() { var state = projectModel.stateListModel.reloadStateFromFromProject(scenarioList.currentIndex) restored(state) loaded(state) } - } - Button - { + + ScenarioButton { id: saveScenario text: qsTr("Save") onClicked: { projectModel.saveProjectFile() saved(state) } + Layout.preferredWidth: 100 + Layout.preferredHeight: 30 + buttonShortcut: "" + sourceImg: "qrc:/qml/img/saveIcon@2x.png" } - Button + + ScenarioButton { id: duplicateScenario text: qsTr("Duplicate") @@ -73,5 +80,9 @@ RowLayout projectModel.stateListModel.save() duplicated(state) } + Layout.preferredWidth: 100 + Layout.preferredHeight: 30 + buttonShortcut: "" + sourceImg: "qrc:/qml/img/duplicateIcon@2x.png" } } diff --git a/mix/qml/StateListModel.qml b/mix/qml/StateListModel.qml index d08ed668d..44873e8db 100644 --- a/mix/qml/StateListModel.qml +++ b/mix/qml/StateListModel.qml @@ -16,7 +16,9 @@ Item { property string defaultAccount: "cb73d9408c4720e230387d956eb0f829d8a4dd2c1055f96257167e14e7169074" //support for old project function fromPlainStateItem(s) { - if (!s.accounts) + console.log("èèèèèèèèèèèè"); + console.log(s); + if (!s.accounts) s.accounts = [stateListModel.newAccount("1000000", QEther.Ether, defaultAccount)]; //support for old project if (!s.contracts) s.contracts = []; @@ -137,7 +139,6 @@ Item { } function toPlainTransactionItem(t) { - console.log(JSON.stringify(t)); var r = { type: t.type, contractId: t.contractId, diff --git a/mix/qml/img/duplicateIcon.png b/mix/qml/img/duplicateIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..b3a2554208e3c2a942a9bfa9484a422c6d8a138e GIT binary patch literal 1020 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 KMNUMnLSTZ1M@~2Z literal 0 HcmV?d00001 diff --git a/mix/qml/img/recycle-discard.png b/mix/qml/img/recycle-discard.png new file mode 100644 index 0000000000000000000000000000000000000000..af1d0959435e93e4d5f55ae572e5b60c42b567c9 GIT binary patch literal 723 zcmV;^0xbQBP)Px%jY&j7R7ef&RZU1#Q562pozX@o9j9p=eUG3BgCK|*TSP);KMTR4l`W#6jV_{v z?IRbtX&KU{bwO>aMKV&PP+6jlLl8j(wdt8DL>fdh&OM#03_J#3^Lz^-mVVsQ0*K7OO1pK{WK|8|Wp7b+qhSiY%A>8vU}h1I zwU9L)CYqQ+^A0b+NC963QUNI>WI;AW`s5ac4OZnbv#Te%fPZ` zK1zhBA{rW`rer&>WG4YJRUd&eFbzAQlsYLV|H548>csqqw015r_$Dz<^da6`x^x|yUsncluhVeuG4n%3xRHmw&ut4N=dja~los>Ky5%FlT3x+C zYf5~U=E#2XFCU*7sPC1OhM{THE7&ZojF3H_Mryag9LDzrd78Hg+&hj`)XOjIWpL|d zm)fkg!quF%9BDqX=3)u-UasX`NYMx}pNF)=dJ2uq!TKTanAFTEnHPUzp=kU!8ooC0 z5zgHXSlx=LABy7Zfk;Z6?~vA?!KxjSqBXscicpd+^jo^)q}Hn={Xk(O@}N4Bo)D6E z*kFFYLfg#UF0{sL+Cw$WlO6TAQb002ovPDHLk FV1gLqOIZK_ literal 0 HcmV?d00001 diff --git a/mix/qml/img/recycle-discard@2x.png b/mix/qml/img/recycle-discard@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..c51c21d21199ede62c15ebb50e7635af58e1bfbe GIT binary patch literal 1568 zcmV+*2H*LKP)Px)+DSw~RA>e5S!-+*RTTct?6#Dp@~A+|u0gCyM1^z#K|~TUL@>oC0SQqO!!MMm zA%sXm(D+BA(I_MkA^L~J00}XuXh?iSssuyZ-4K5eQ3wHd1vP?DD5X2c?@pO^y4`Mf zw^J%QO=s`xoO93l=G=47y#oY)0RjO60RjO60RjO60RjO60RjO60RjO6*9L(mjGLCQ zqB|QAjpUm#ftm?PiGKP6VmIca>(7|gALdec6Bu*5CGv$pmV^Xf9>DObTyh#wJsA=@ z0Fi~|g3tG%dRQ*H{`OsS0Dy44h>S6cvz#?lDjN=>>L#xt^pH6r3GWxdIEN0HG8)!Y zFO6Sy@k>xKauSF>PvbTcfsPlTda_;d&~&7ZaO^Pxvjc((BU2UUY_%VmhIB(Qa}-KD zC;%Acl87y#k=yx{o3^U{DXLpkWE}wrb@U-^>y-u5aOSXS55(V~0bq=2Ms%Jf_?Vth znQa{3{LwaTpFb0)k7tkh*&b8?j3H)62#M?`2wgjZ>hTuM+&dem&-iIbcH)#1|DNe_Eta zk~bl?&=TE7nWB(Q361_3N9z0HCH3U!p=3{z!h1}VR+SC3@nkM8wWT>%e_wqH{hBlh zL&rR!jGpyT0wYKE#aGC7BVFPz*FMIHpS!Sz+`075yrzB zwl!ORDQ({Ya1;b)QOVKS3MpEhx0u~uNP7lSC%Jr9xU>vji@A$DEnd3LN9p7i>dnx0Dba_&dF8ZoeQ*gwu`LrR(K{e$A*chnVpOEing!it9RrxIati( z%kjEgwE6n{1ps=tJ6S6(m$c>&p}Ll5fE{5ge2{?N4_IZcOmBG)P9I}C>GTPPFg+;g z+kvl{AhWc;8C1p^rOHu0neKaL3DD*!*~d=gY5+0MMcx9x z^b^v1Z$oSqx6bv<@J4mxEx4gOd2_V1U~&(kuO49AZL3AfA7or|K72Uy@Jw(OWpk@j z#xFw7eZLtaGUsa%9WItmB1F6jEB<{D&|MeomX*$2CHxdWV;_?^TcI^><( zK(+#}a@pQVt!r7H=RLqsRFyM63}IK~XQWRtMr6D^=7WifzC|w@Z~A#rW`ZlP)Z^~S(6nb;i-?;+*0D%C30D%C30D%C30D=D<0{;O2V5305 SQ6=#J0000Px%b4f%&R7ef&mCb7tK^VrHY!bTEARbz%he$qbz$isL8bmSVON+(7!GlPVib%ne zs0S51cn}1^yP~Lw`7)A#ARpHZZ`f#Tqw(~-EDi)3=A{#=AGwx z-e+bfBO}8$bl`t?z_VEca=BdEDVNJj43CJ<(y#&33`V+WGSYS82ESLgsK}+DvF(I}*S}`^xz)&{ydiA~ZA5+O;gpIyq-?;o91`)!dN)Hc9|q zrnjhWFBZSD0yAO={(;b|th3^!G~!mHuyfr8NFMS8#3yUD+DA5s{@2!OwQh$(p)({2 z7brGdm#8ds1A|bUJ-VWcU?5pj*a>j-Xf&J6cd=OP8zAF=jsY4FM2w4E zH1Y1AW<4cH#7IBLbed5iXTDOY*#1kpeuxB#RpSUw;M7eVIdAnyS?$^KSR#=Ka0e!~ f9C!%$Pdo4n78mV*6YJYD00000NkvXXu0mjf;|oPn literal 0 HcmV?d00001 diff --git a/mix/qml/img/recycle-icon@2x.png b/mix/qml/img/recycle-icon@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..75b590b2adb7698c418a65899f13189bf8b3fa92 GIT binary patch literal 1435 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 literal 0 HcmV?d00001 diff --git a/mix/qml/img/restoreIcon@2x.png b/mix/qml/img/restoreIcon@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..3160b0bf348f7a9b2136ffa84c8eb11f19afbac2 GIT binary patch literal 2447 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 N002ovPDHLkV1ho6ksSa4 literal 0 HcmV?d00001 diff --git a/mix/qml/img/saveIcon.png b/mix/qml/img/saveIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..46e17522b27729f5d8ad767813183ce12f2bfe03 GIT binary patch literal 1068 zcmV+{1k?M8P)Px&=1D|BR7ef&RcmZhRUH4_wztoIWb7f$^i7EDlUCDpLn+O4-WTm}Hb7bJ@(8Y&g+bU|q}BuCLp7@A2G9DXl6Du}F6eXf;GDB#mB9e7*N*^E!_6gVwXk#l_JYpk00=zMnb@?Ugyj=) zxExo}+uebaeSPryIZXdLgj9&?kju#{rJ<ORzI3|KF)pgoZy8YL1E31m03lDe1X>an7!VP4z~u=7@r*-}1}_>!K|sY$&>xaOHk%Cx zzwAJHc^RH~dk>T@4}1?l2#1FQAEp4ZB+(-}IXM(8S+izPx-@kvBMRA>e5S_yDd#~J=~+p>H}U>O^1zy}7*;b0SNns7{;k}@PFOhPEr($bkU zEkn~Jq?rKIHti6awqbw*F-@kB(o6u8q=eIu!!dUVPz<(ABIDbZEy;JPzD7$LR2gBRxcDoly zB$7Zs8LQ3qFEPVxSiLw+AK1WEdDJ7}z{L*bk*nsncs#*%hM^afpZo~zZLM(F?a*mE zarX3a9_4ne5zFG#WmiqVezl@P$d&UxxuX^d2QTQ-gko_ic)TS zxdKV#7XUyYyT)U8eRtKuv9*E3NR&AR;m~FMG@(GW-C*ciB8iDbTwI*rW=(r5Qqv~* z>-`HBiy86p2|;AD#pF(qC2pf_J+G}?th5F-j-bLB2ya&!Hp``=SIOuLP2ENu{ooL? zr%WY4$Y3-W(AwIJAOG~3u%@3l_915H&q1;>1$EB?@(BI2@?w|ZBB|mMje&_X06CWV#hu-j1a z=^0f0=NhVS--OL(#k}J0kPStMHlr)PS?`gbD|_Q`SOG(5;3N{BDytE@FIGCO#!e(E zC!nBc0kYD^LBJoV&f|7NC<MeezI6H0Ij~N%iEX>1sz$f* zn?qxqOy&*$m;@!%S~oP^y#Vxek4TA=J=jAzL^S2;Gmto^X;9&Ks~TC;3h?0ExrmpF zz3qmsE*#jm7c#O4vS$T$h*$k+t+&nLqS?@g)k*is;-JI{2tq-uI0%GZ!)Y?&>RVUP zR9Ax;1@rO1%sebzwjA~KYUs6E?;0^FGmA`*7_=B%=&}X?$$|4ek(_`aiE;ajcmZ;9rz3Z2o_9LvEgm##9H6)z{6KTS2?%XAPuIkhL`_4hJ~c>N zzlz1siHeg)pvuTb!MulIqhsOp1g{zWx_GNR@XmNZZ4A{m9NNI;dN@+T^x0Q-cGvmq zs`V`zV;GJ;az`#;Y|_QESUYyHY{3EB#7Pg3ORxE2aT|h3I-u^G93c-35atK*L{sb z@;jSffXmra;UP!p{)vQme-c1Z$o%9(_#7$V#qQVG{j?^F08#& ziTau<94{YE`}zVXgVBGB#{3*4Sh+9}Z0*Qb)dom_{au})a>_DT{?5L`%do2-m%w+6X& zmk|HxVxJvBd2D_jvagpTdB-16PhO#$bUJhr=Ph>kH+ydo_sA;|J1hm75^ooit90;a z)f4BNo0~8_FAs(JGm)YkiwW=Ug6+x;XxDFstFZ+FMG}%<-vq_eC1}^{&~djOCYuW` z54ZPfPC#I!F0m)@WvLe-4~dRjRaK}{t1)NJ1DH8I7s{!b$gcVroqyU5<;&}!BQMd_ zq}^!gf!!JY&=d&zNXwjn;Bg84(;<|BcJhpN;lf3zRCiERG#5FOGmx?2=TNt{psU*o zi-Uyyy`L3Ai5?b>6A)~AepgCLvZk#~Gw79Y(v+@7AMROC(1eLGGX8@y8bn0j+^@aaeCtCE{pH$yWoXc|>BBMktn zCA{W78zNHLx^-(ZUm!W$(A2cZ?V$$fokc#mWo1tZ(nZ3aWqb=R>UWPlwwSa3Dhx0t z$O;ZBJ9oZW&}}v!Y;JAMAx`==%qG|A%xv#>MlX$w{-+*>dVa-{#npZ$jtZj=g3phg zyGvJfbacMisny9@TK=3uOwP<^FJE=!MD)_*k1qJg$IErj)!pHqc9)+zS$)2;;;(lb z8u>0~Pq9Lg>`F?KZ|*U5tXWaARCP}Q-!_Ild-ljmOG{^b+x&|96Gb43Koo%}0#O8_ d2>kye@L$z5UIt#?B{~2A002ovPDHLkV1i06dM5w? literal 0 HcmV?d00001 diff --git a/mix/res.qrc b/mix/res.qrc index ac0af57ac..e84f77d84 100644 --- a/mix/res.qrc +++ b/mix/res.qrc @@ -68,5 +68,17 @@ qml/img/warningicon.png qml/img/warningicon@2x.png qml/QAddressView.qml + qml/img/recycle-discard.png + qml/img/recycle-discard@2x.png + qml/img/recycle-icon.png + qml/img/recycle-icon@2x.png + qml/img/recycle-keep.png + qml/img/recycle-keep@2x.png + qml/img/restoreIcon.png + qml/img/restoreIcon@2x.png + qml/img/saveIcon.png + qml/img/saveIcon@2x.png + qml/img/duplicateIcon.png + qml/img/duplicateIcon@2x.png