mirror of
https://github.com/monero-project/monero-gui.git
synced 2024-12-22 19:49:34 +00:00
Wizard: mobile redesign
This commit is contained in:
parent
e826f7c1ec
commit
ebcab010bb
13 changed files with 307 additions and 345 deletions
|
@ -85,11 +85,10 @@ Item {
|
|||
horizontalAlignment: Text.AlignHCenter
|
||||
font.family: "Arial"
|
||||
font.bold: true
|
||||
font.letterSpacing: -1
|
||||
font.pixelSize: button.fontSize
|
||||
color: parent.textColor
|
||||
visible: parent.icon === ""
|
||||
font.capitalization : Font.AllUppercase
|
||||
font.capitalization : Font.Capitalize
|
||||
}
|
||||
|
||||
Image {
|
||||
|
|
9
main.qml
9
main.qml
|
@ -67,6 +67,7 @@ ApplicationWindow {
|
|||
property int timeToUnlock: 0
|
||||
property bool qrScannerEnabled: builtWithScanner && (QtMultimedia.availableCameras.length > 0)
|
||||
property int blocksToSync: 1
|
||||
property var isMobile: (appWindow.width > 700) ? false : true
|
||||
|
||||
// true if wallet ever synchronized
|
||||
property bool walletInitialized : false
|
||||
|
@ -191,7 +192,6 @@ ApplicationWindow {
|
|||
}
|
||||
|
||||
walletManager.setDaemonAddress(persistentSettings.daemon_address)
|
||||
|
||||
// wallet already opened with wizard, we just need to initialize it
|
||||
if (typeof wizard.settings['wallet'] !== 'undefined') {
|
||||
console.log("using wizard wallet")
|
||||
|
@ -237,6 +237,7 @@ ApplicationWindow {
|
|||
|
||||
function connectWallet(wallet) {
|
||||
currentWallet = wallet
|
||||
walletName = usefulName(wallet.path)
|
||||
updateSyncing(false)
|
||||
|
||||
viewOnly = currentWallet.viewOnly;
|
||||
|
@ -1137,7 +1138,7 @@ ApplicationWindow {
|
|||
}
|
||||
}
|
||||
|
||||
property int maxWidth: leftPanel.width + 655 + rightPanel.width
|
||||
property int minWidth: 326
|
||||
property int minHeight: 720
|
||||
MouseArea {
|
||||
id: resizeArea
|
||||
|
@ -1171,9 +1172,9 @@ ApplicationWindow {
|
|||
var dx = previousPosition.x - pos.x
|
||||
var dy = previousPosition.y - pos.y
|
||||
|
||||
if(appWindow.width - dx > parent.maxWidth)
|
||||
if(appWindow.width - dx > parent.minWidth)
|
||||
appWindow.width -= dx
|
||||
else appWindow.width = parent.maxWidth
|
||||
else appWindow.width = parent.minWidth
|
||||
|
||||
if(appWindow.height - dy > parent.minHeight)
|
||||
appWindow.height -= dy
|
||||
|
|
|
@ -28,10 +28,11 @@
|
|||
|
||||
import moneroComponents.WalletManager 1.0
|
||||
import QtQuick 2.2
|
||||
import QtQuick.Layouts 1.1
|
||||
import "../components"
|
||||
import "utils.js" as Utils
|
||||
|
||||
Item {
|
||||
ColumnLayout {
|
||||
|
||||
id: passwordPage
|
||||
opacity: 0
|
||||
|
@ -55,29 +56,6 @@ Item {
|
|||
return wizard.walletPathValid(walletFullPath);
|
||||
}
|
||||
|
||||
Row {
|
||||
id: dotsRow
|
||||
anchors.top: parent.top
|
||||
anchors.right: parent.right
|
||||
anchors.topMargin: 85
|
||||
spacing: 6
|
||||
|
||||
ListModel {
|
||||
id: dotsModel
|
||||
ListElement { dotColor: "#FFE00A" }
|
||||
ListElement { dotColor: "#DBDBDB" }
|
||||
}
|
||||
|
||||
Repeater {
|
||||
model: dotsModel
|
||||
delegate: Rectangle {
|
||||
width: 12; height: 12
|
||||
radius: 6
|
||||
color: dotColor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WizardManageWalletUI {
|
||||
id: uiItem
|
||||
titleText: qsTr("Create view only wallet") + translationManager.emptyString
|
||||
|
@ -88,7 +66,6 @@ Item {
|
|||
recoverMode: false
|
||||
}
|
||||
|
||||
|
||||
Component.onCompleted: {
|
||||
//parent.wizardRestarted.connect(onWizardRestarted)
|
||||
}
|
||||
|
|
|
@ -29,11 +29,11 @@
|
|||
import QtQuick 2.2
|
||||
import moneroComponents.WalletManager 1.0
|
||||
import moneroComponents.Wallet 1.0
|
||||
|
||||
import QtQuick.Layouts 1.1
|
||||
import QtQuick.Dialogs 1.2
|
||||
import 'utils.js' as Utils
|
||||
|
||||
Item {
|
||||
ColumnLayout {
|
||||
opacity: 0
|
||||
visible: false
|
||||
|
||||
|
@ -97,7 +97,6 @@ Item {
|
|||
WizardManageWalletUI {
|
||||
id: uiItem
|
||||
titleText: qsTr("Create a new wallet") + translationManager.emptyString
|
||||
wordsTextTitle: qsTr("Here is your wallet's 25 word mnemonic seed") + translationManager.emptyString
|
||||
wordsTextItem.clipboardButtonVisible: true
|
||||
wordsTextItem.tipTextVisible: true
|
||||
wordsTextItem.memoTextReadOnly: true
|
||||
|
|
|
@ -27,8 +27,12 @@
|
|||
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
import QtQuick 2.2
|
||||
import QtQuick.Layouts 1.1
|
||||
|
||||
Item {
|
||||
|
||||
ColumnLayout {
|
||||
Layout.leftMargin: wizardLeftMargin
|
||||
Layout.rightMargin: wizardRightMargin
|
||||
opacity: 0
|
||||
visible: false
|
||||
Behavior on opacity {
|
||||
|
@ -70,9 +74,15 @@ Item {
|
|||
}
|
||||
|
||||
function updateSettingsSummary() {
|
||||
settingsText.text = qsTr("New wallet details:") + translationManager.emptyString
|
||||
+ "<br>"
|
||||
+ buildSettingsString();
|
||||
if (!isMobile){
|
||||
settingsText.text = qsTr("New wallet details:") + translationManager.emptyString
|
||||
+ "<br>"
|
||||
+ buildSettingsString();
|
||||
} else {
|
||||
settingsText.text = qsTr("Don't forget to write down your seed. You can view your seed and change your settings on settings page.")
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
function onPageOpened(settings) {
|
||||
|
@ -81,12 +91,9 @@ Item {
|
|||
}
|
||||
|
||||
|
||||
Row {
|
||||
RowLayout {
|
||||
id: dotsRow
|
||||
anchors.top: parent.top
|
||||
anchors.right: parent.right
|
||||
anchors.topMargin: 85
|
||||
spacing: 6
|
||||
Layout.alignment: Qt.AlignRight
|
||||
|
||||
ListModel {
|
||||
id: dotsModel
|
||||
|
@ -106,19 +113,12 @@ Item {
|
|||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
ColumnLayout {
|
||||
id: headerColumn
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.leftMargin: 16
|
||||
anchors.rightMargin: 16
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 74
|
||||
spacing: 24
|
||||
Layout.fillWidth: true
|
||||
|
||||
Text {
|
||||
anchors.left: parent.left
|
||||
width: headerColumn.width - dotsRow.width - 16
|
||||
Layout.fillWidth: true
|
||||
font.family: "Arial"
|
||||
font.pixelSize: 28
|
||||
wrapMode: Text.Wrap
|
||||
|
@ -129,9 +129,8 @@ Item {
|
|||
}
|
||||
|
||||
Text {
|
||||
Layout.fillWidth: true
|
||||
id: settingsText
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
font.family: "Arial"
|
||||
font.pixelSize: 16
|
||||
wrapMode: Text.Wrap
|
||||
|
|
|
@ -29,16 +29,21 @@
|
|||
import QtQuick 2.2
|
||||
import Qt.labs.settings 1.0
|
||||
import QtQuick.Dialogs 1.2
|
||||
import QtQuick.Layouts 1.2
|
||||
import QtQuick.Layouts 1.1
|
||||
|
||||
import "../components"
|
||||
|
||||
GridLayout {
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
Layout.fillHeight: true
|
||||
id: wizard
|
||||
property alias nextButton : nextButton
|
||||
property var settings : ({})
|
||||
property int currentPage: 0
|
||||
property int wizardLeftMargin: (!isMobile) ? 150 : 25
|
||||
property int wizardRightMargin: (!isMobile) ? 150 : 25
|
||||
property int wizardBottomMargin: (isMobile) ? 150 : 25
|
||||
property int wizardTopMargin: (isMobile) ? 15 : 50
|
||||
|
||||
property var paths: {
|
||||
// "create_wallet" : [welcomePage, optionsPage, createWalletPage, passwordPage, donationPage, finishPage ],
|
||||
|
@ -86,14 +91,20 @@ GridLayout {
|
|||
}
|
||||
console.log("switchpage: currentPage: ", currentPage);
|
||||
|
||||
// Update prev/next button positions for mobile/desktop
|
||||
prevButton.anchors.verticalCenter = (!isMobile) ? wizard.verticalCenter : undefined
|
||||
prevButton.anchors.bottom = (isMobile) ? wizard.bottom : undefined
|
||||
nextButton.anchors.verticalCenter = (!isMobile) ? wizard.verticalCenter : undefined
|
||||
nextButton.anchors.bottom = (isMobile) ? wizard.bottom : undefined
|
||||
|
||||
if (currentPage > 0 || currentPage < pages.length - 1) {
|
||||
pages[currentPage].opacity = 0
|
||||
var step_value = next ? 1 : -1
|
||||
currentPage += step_value
|
||||
pages[currentPage].opacity = 1;
|
||||
|
||||
var nextButtonVisible = pages[currentPage] !== optionsPage && currentPage < pages.length - 1;
|
||||
nextButton.visible = nextButtonVisible;
|
||||
var nextButtonVisible = currentPage > 1 && currentPage < pages.length - 1
|
||||
nextButton.visible = nextButtonVisible
|
||||
|
||||
if (typeof pages[currentPage].onPageOpened !== 'undefined') {
|
||||
pages[currentPage].onPageOpened(settings,next)
|
||||
|
@ -227,50 +238,17 @@ GridLayout {
|
|||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: nextButton
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 50
|
||||
visible: wizard.currentPage !== 1 && wizard.currentPage !== 6
|
||||
width: 50; height: 50
|
||||
radius: 25
|
||||
color: enabled ? nextArea.containsMouse ? "#FF4304" : "#FF6C3C" : "#DBDBDB"
|
||||
|
||||
|
||||
Image {
|
||||
anchors.centerIn: parent
|
||||
anchors.horizontalCenterOffset: 3
|
||||
source: "qrc:///images/nextPage.png"
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: nextArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
onClicked: wizard.switchPage(true)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
WizardWelcome {
|
||||
id: welcomePage
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.right: nextButton.left
|
||||
anchors.left: prevButton.right
|
||||
anchors.leftMargin: 50
|
||||
anchors.rightMargin: 50
|
||||
// Layout.bottomMargin: wizardBottomMargin
|
||||
Layout.topMargin: wizardTopMargin
|
||||
|
||||
}
|
||||
|
||||
WizardOptions {
|
||||
id: optionsPage
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.right: nextButton.left
|
||||
anchors.left: prevButton.right
|
||||
anchors.leftMargin: 50
|
||||
anchors.rightMargin: 50
|
||||
Layout.bottomMargin: wizardBottomMargin
|
||||
Layout.topMargin: wizardTopMargin
|
||||
onCreateWalletClicked: wizard.openCreateWalletPage()
|
||||
onRecoveryWalletClicked: wizard.openRecoveryWalletPage()
|
||||
onOpenWalletClicked: wizard.openOpenWalletPage();
|
||||
|
@ -278,69 +256,46 @@ GridLayout {
|
|||
|
||||
WizardCreateWallet {
|
||||
id: createWalletPage
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.right: nextButton.left
|
||||
anchors.left: prevButton.right
|
||||
anchors.leftMargin: 50
|
||||
anchors.rightMargin: 50
|
||||
Layout.bottomMargin: wizardBottomMargin
|
||||
Layout.topMargin: wizardTopMargin
|
||||
}
|
||||
|
||||
WizardCreateViewOnlyWallet {
|
||||
id: createViewOnlyWalletPage
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.right: nextButton.left
|
||||
anchors.left: prevButton.right
|
||||
anchors.leftMargin: 50
|
||||
anchors.rightMargin: 50
|
||||
Layout.bottomMargin: wizardBottomMargin
|
||||
Layout.topMargin: wizardTopMargin
|
||||
}
|
||||
|
||||
WizardRecoveryWallet {
|
||||
id: recoveryWalletPage
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.right: nextButton.left
|
||||
anchors.left: prevButton.right
|
||||
anchors.leftMargin: 50
|
||||
anchors.rightMargin: 50
|
||||
Layout.bottomMargin: wizardBottomMargin
|
||||
Layout.topMargin: wizardTopMargin
|
||||
}
|
||||
|
||||
WizardPassword {
|
||||
id: passwordPage
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.right: nextButton.left
|
||||
anchors.left: prevButton.right
|
||||
anchors.leftMargin: 50
|
||||
anchors.rightMargin: 50
|
||||
Layout.bottomMargin: wizardBottomMargin
|
||||
Layout.topMargin: wizardTopMargin
|
||||
}
|
||||
|
||||
WizardDonation {
|
||||
id: donationPage
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.right: nextButton.left
|
||||
anchors.left: prevButton.right
|
||||
anchors.leftMargin: 50
|
||||
anchors.rightMargin: 50
|
||||
Layout.bottomMargin: wizardBottomMargin
|
||||
Layout.topMargin: wizardTopMargin
|
||||
}
|
||||
|
||||
WizardFinish {
|
||||
id: finishPage
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.right: nextButton.left
|
||||
anchors.left: prevButton.right
|
||||
anchors.leftMargin: 50
|
||||
anchors.rightMargin: 50
|
||||
Layout.bottomMargin: wizardBottomMargin
|
||||
Layout.topMargin: wizardTopMargin
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: prevButton
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.verticalCenter: wizard.verticalCenter
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 50
|
||||
anchors.leftMargin: isMobile ? 20 : 50
|
||||
anchors.bottomMargin: isMobile ? 20 : 50
|
||||
visible: parent.currentPage > 0
|
||||
|
||||
width: 50; height: 50
|
||||
|
@ -361,12 +316,37 @@ GridLayout {
|
|||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: nextButton
|
||||
anchors.verticalCenter: wizard.verticalCenter
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: isMobile ? 20 : 50
|
||||
anchors.bottomMargin: isMobile ? 20 : 50
|
||||
visible: currentPage > 1 && currentPage < pages.length - 1
|
||||
width: 50; height: 50
|
||||
radius: 25
|
||||
color: enabled ? nextArea.containsMouse ? "#FF4304" : "#FF6C3C" : "#DBDBDB"
|
||||
|
||||
|
||||
Image {
|
||||
anchors.centerIn: parent
|
||||
anchors.horizontalCenterOffset: 3
|
||||
source: "qrc:///images/nextPage.png"
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: nextArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
onClicked: wizard.switchPage(true)
|
||||
}
|
||||
}
|
||||
|
||||
StandardButton {
|
||||
id: sendButton
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.margins: 50
|
||||
width: 110
|
||||
anchors.margins: (isMobile) ? 20 : 50
|
||||
text: qsTr("USE MONERO") + translationManager.emptyString
|
||||
shadowReleasedColor: "#FF4304"
|
||||
shadowPressedColor: "#B32D00"
|
||||
|
@ -383,8 +363,7 @@ GridLayout {
|
|||
id: createViewOnlyWalletButton
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.margins: 50
|
||||
width: 110
|
||||
anchors.margins: (isMobile) ? 20 : 50
|
||||
text: qsTr("Create wallet") + translationManager.emptyString
|
||||
shadowReleasedColor: "#FF4304"
|
||||
shadowPressedColor: "#B32D00"
|
||||
|
@ -416,8 +395,7 @@ GridLayout {
|
|||
id: abortViewOnlyButton
|
||||
anchors.right: createViewOnlyWalletButton.left
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.margins: 50
|
||||
width: 110
|
||||
anchors.margins: (isMobile) ? 20 : 50
|
||||
text: qsTr("Abort") + translationManager.emptyString
|
||||
shadowReleasedColor: "#FF4304"
|
||||
shadowPressedColor: "#B32D00"
|
||||
|
|
|
@ -33,16 +33,13 @@ import QtQuick.Layouts 1.2
|
|||
import "../components"
|
||||
import 'utils.js' as Utils
|
||||
|
||||
// Reusable component for managing wallet (account name, path, private key)
|
||||
|
||||
// Reusable component for mnaging wallet (account name, path, private key)
|
||||
ColumnLayout {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
spacing: 5
|
||||
|
||||
id: page
|
||||
Layout.leftMargin: wizardLeftMargin
|
||||
Layout.rightMargin: wizardRightMargin
|
||||
property alias titleText: titleText.text
|
||||
property alias accountNameText: accountName.text
|
||||
property alias wordsTextTitle: frameHeader.text
|
||||
property alias walletPath: fileUrlInput.text
|
||||
property alias wordsTextItem : memoTextItem
|
||||
property alias restoreHeight : restoreHeightItem.text
|
||||
|
@ -90,7 +87,6 @@ ColumnLayout {
|
|||
|
||||
RowLayout {
|
||||
id: dotsRow
|
||||
Layout.topMargin: 85
|
||||
Layout.alignment: Qt.AlignRight
|
||||
spacing: 6
|
||||
|
||||
|
@ -115,6 +111,7 @@ ColumnLayout {
|
|||
|
||||
RowLayout {
|
||||
id: headerColumn
|
||||
Layout.fillWidth: true
|
||||
Text {
|
||||
Layout.fillWidth: true
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
|
@ -127,18 +124,20 @@ ColumnLayout {
|
|||
}
|
||||
|
||||
ColumnLayout {
|
||||
Layout.bottomMargin: rowSpacing
|
||||
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 20
|
||||
fontSize: 14
|
||||
text: qsTr("Wallet name")
|
||||
+ translationManager.emptyString
|
||||
text: qsTr("Wallet name")
|
||||
+ translationManager.emptyString
|
||||
}
|
||||
|
||||
LineEdit {
|
||||
id: accountName
|
||||
Layout.fillWidth: true
|
||||
Layout.maximumWidth: 600
|
||||
Layout.minimumWidth: 200
|
||||
text: defaultAccountName
|
||||
onTextUpdated: checkNextButton()
|
||||
}
|
||||
|
@ -146,6 +145,7 @@ ColumnLayout {
|
|||
|
||||
RowLayout{
|
||||
visible: recoverMode
|
||||
spacing: 0
|
||||
StandardButton {
|
||||
id: recoverFromSeedButton
|
||||
text: qsTr("Restore from seed") + translationManager.emptyString
|
||||
|
@ -182,31 +182,39 @@ ColumnLayout {
|
|||
WizardMemoTextInput {
|
||||
id : memoTextItem
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredWidth: 600
|
||||
Layout.minimumWidth: 300
|
||||
Layout.maximumWidth: 600
|
||||
Layout.minimumWidth: 200
|
||||
}
|
||||
}
|
||||
|
||||
// Recover from keys
|
||||
GridLayout {
|
||||
Layout.bottomMargin: page.rowSpacing
|
||||
rowSpacing: page.rowSpacing
|
||||
id: recoverFromKeys
|
||||
visible: recoverMode && !recoverFromSeedMode
|
||||
columns: 1
|
||||
LineEdit {
|
||||
Layout.fillWidth: true
|
||||
id: addressLine
|
||||
Layout.maximumWidth: 600
|
||||
Layout.minimumWidth: 200
|
||||
placeholderText: qsTr("Account address (public)")
|
||||
onTextUpdated: checkNextButton()
|
||||
}
|
||||
LineEdit {
|
||||
Layout.fillWidth: true
|
||||
id: viewKeyLine
|
||||
Layout.maximumWidth: 600
|
||||
Layout.minimumWidth: 200
|
||||
placeholderText: qsTr("View key (private)")
|
||||
onTextUpdated: checkNextButton()
|
||||
|
||||
}
|
||||
LineEdit {
|
||||
Layout.fillWidth: true
|
||||
Layout.maximumWidth: 600
|
||||
Layout.minimumWidth: 200
|
||||
id: spendKeyLine
|
||||
placeholderText: qsTr("Spend key (private)")
|
||||
onTextUpdated: checkNextButton()
|
||||
|
@ -225,12 +233,14 @@ ColumnLayout {
|
|||
color: "#4A4646"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Restore Height
|
||||
RowLayout {
|
||||
// Restore Height
|
||||
visible: restoreHeightItem.visible // Prevents empty RowLayout bug
|
||||
LineEdit {
|
||||
id: restoreHeightItem
|
||||
Layout.preferredWidth: 250
|
||||
Layout.maximumWidth: 600
|
||||
Layout.minimumWidth: 200
|
||||
placeholderText: qsTr("Restore height (optional)")
|
||||
validator: IntValidator {
|
||||
bottom:0
|
||||
|
@ -238,8 +248,8 @@ ColumnLayout {
|
|||
}
|
||||
}
|
||||
|
||||
// Wallet store location
|
||||
ColumnLayout {
|
||||
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: 20
|
||||
|
@ -250,8 +260,11 @@ ColumnLayout {
|
|||
|
||||
LineEdit {
|
||||
Layout.fillWidth: true
|
||||
Layout.maximumWidth: 600
|
||||
Layout.minimumWidth: 200
|
||||
id: fileUrlInput
|
||||
text: moneroAccountsDir + "/"
|
||||
|
||||
// workaround for the bug "filechooser only opens once"
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
|
|
|
@ -31,14 +31,15 @@ import QtQml 2.2
|
|||
import QtQuick.Layouts 1.1
|
||||
import "../components"
|
||||
|
||||
Item {
|
||||
ColumnLayout {
|
||||
id: page
|
||||
signal createWalletClicked()
|
||||
signal recoveryWalletClicked()
|
||||
signal openWalletClicked()
|
||||
opacity: 0
|
||||
visible: false
|
||||
property var buttonSize: 190
|
||||
property int buttonSize: (isMobile) ? 80 : 190
|
||||
property int buttonImageSize: (isMobile) ? buttonSize - 10 : buttonSize - 30
|
||||
|
||||
function onPageClosed() {
|
||||
// Save settings used in open from file.
|
||||
|
@ -68,19 +69,15 @@ Item {
|
|||
|
||||
onOpacityChanged: visible = opacity !== 0
|
||||
|
||||
Column {
|
||||
ColumnLayout {
|
||||
id: headerColumn
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 74
|
||||
anchors.leftMargin: 16
|
||||
anchors.rightMargin: 16
|
||||
spacing: 24
|
||||
Layout.leftMargin: wizardLeftMargin
|
||||
Layout.rightMargin: wizardRightMargin
|
||||
Layout.bottomMargin: (!isMobile) ? 40 : 20
|
||||
spacing: 30
|
||||
|
||||
Text {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
Layout.fillWidth: true
|
||||
font.family: "Arial"
|
||||
font.pixelSize: 28
|
||||
//renderType: Text.NativeRendering
|
||||
|
@ -91,8 +88,7 @@ Item {
|
|||
}
|
||||
|
||||
Text {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
Layout.fillWidth: true
|
||||
font.family: "Arial"
|
||||
font.pixelSize: 18
|
||||
//renderType: Text.NativeRendering
|
||||
|
@ -103,26 +99,34 @@ Item {
|
|||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
id: selectPath
|
||||
anchors.verticalCenterOffset: 35
|
||||
anchors.centerIn: parent
|
||||
spacing: 40
|
||||
GridLayout {
|
||||
Layout.leftMargin: wizardLeftMargin
|
||||
Layout.rightMargin: wizardRightMargin
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
id: actionButtons
|
||||
columnSpacing: 40
|
||||
rowSpacing: 10
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
flow: isMobile ? GridLayout.TopToBottom : GridLayout.LeftToRight
|
||||
|
||||
|
||||
Column {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: 30
|
||||
GridLayout {
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
flow: !isMobile ? GridLayout.TopToBottom : GridLayout.LeftToRight
|
||||
rowSpacing: 20
|
||||
columnSpacing: 10
|
||||
|
||||
Rectangle {
|
||||
width: page.buttonSize; height: page.buttonSize
|
||||
Layout.preferredHeight: page.buttonSize
|
||||
Layout.preferredWidth: page.buttonSize
|
||||
radius: page.buttonSize
|
||||
color: createWalletArea.containsMouse ? "#DBDBDB" : "#FFFFFF"
|
||||
|
||||
|
||||
Image {
|
||||
width:page.buttonSize -30
|
||||
height:page.buttonSize -30
|
||||
width: page.buttonImageSize
|
||||
height: page.buttonImageSize
|
||||
fillMode: Image.PreserveAspectFit
|
||||
horizontalAlignment: Image.AlignRight
|
||||
verticalAlignment: Image.AlignTop
|
||||
|
@ -142,28 +146,32 @@ Item {
|
|||
}
|
||||
|
||||
Text {
|
||||
Layout.preferredWidth: 190
|
||||
font.family: "Arial"
|
||||
font.pixelSize: 16
|
||||
color: "#4A4949"
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
width:page.buttonSize
|
||||
wrapMode: Text.WordWrap
|
||||
text: qsTr("Create a new wallet") + translationManager.emptyString
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: 30
|
||||
GridLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
flow: !isMobile ? GridLayout.TopToBottom : GridLayout.LeftToRight
|
||||
rowSpacing: 20
|
||||
columnSpacing: 10
|
||||
|
||||
Rectangle {
|
||||
width: page.buttonSize; height: page.buttonSize
|
||||
Layout.preferredHeight: page.buttonSize
|
||||
Layout.preferredWidth: page.buttonSize
|
||||
radius: page.buttonSize
|
||||
color: recoverWalletArea.containsMouse ? "#DBDBDB" : "#FFFFFF"
|
||||
|
||||
Image {
|
||||
width:page.buttonSize -30
|
||||
height:page.buttonSize -30
|
||||
width: page.buttomImageSize
|
||||
height: page.buttonImageSize
|
||||
fillMode: Image.PreserveAspectFit
|
||||
anchors.centerIn: parent
|
||||
source: "qrc:///images/recoverWallet.png"
|
||||
|
@ -181,6 +189,7 @@ Item {
|
|||
}
|
||||
|
||||
Text {
|
||||
Layout.preferredWidth: 190
|
||||
font.family: "Arial"
|
||||
font.pixelSize: 16
|
||||
color: "#4A4949"
|
||||
|
@ -191,18 +200,22 @@ Item {
|
|||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: 30
|
||||
GridLayout {
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
flow: !isMobile ? GridLayout.TopToBottom : GridLayout.LeftToRight
|
||||
rowSpacing: 20
|
||||
columnSpacing: 10
|
||||
|
||||
Rectangle {
|
||||
width: page.buttonSize; height: page.buttonSize
|
||||
Layout.preferredHeight: page.buttonSize
|
||||
Layout.preferredWidth: page.buttonSize
|
||||
radius: page.buttonSize
|
||||
color: openWalletArea.containsMouse ? "#DBDBDB" : "#FFFFFF"
|
||||
|
||||
Image {
|
||||
width:page.buttonSize -30
|
||||
height:page.buttonSize -30
|
||||
width: page.buttonImageSize
|
||||
height: page.buttonImageSize
|
||||
fillMode: Image.PreserveAspectFit
|
||||
anchors.centerIn: parent
|
||||
source: "qrc:///images/openAccount.png"
|
||||
|
@ -220,12 +233,12 @@ Item {
|
|||
}
|
||||
|
||||
Text {
|
||||
Layout.preferredWidth: 190
|
||||
font.family: "Arial"
|
||||
font.pixelSize: 16
|
||||
color: "#4A4949"
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
text: qsTr("Open a wallet from file") + translationManager.emptyString
|
||||
width:page.buttonSize
|
||||
wrapMode: Text.WordWrap
|
||||
}
|
||||
}
|
||||
|
@ -234,34 +247,29 @@ Item {
|
|||
|
||||
}
|
||||
|
||||
// daemon select
|
||||
// TODO: Move to separate page
|
||||
|
||||
ColumnLayout {
|
||||
Layout.leftMargin: wizardLeftMargin
|
||||
Layout.rightMargin: wizardRightMargin
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
|
||||
|
||||
ColumnLayout {
|
||||
anchors.top: selectPath.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.topMargin: 35
|
||||
Label {
|
||||
Layout.topMargin: 20
|
||||
fontSize: 14
|
||||
text: qsTr("Custom daemon address (optional)") + translationManager.emptyString
|
||||
+ translationManager.emptyString
|
||||
}
|
||||
|
||||
spacing: 5
|
||||
GridLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
|
||||
Rectangle {
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
width: 200
|
||||
height: 1
|
||||
color: "gray"
|
||||
}
|
||||
|
||||
Text {
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
font.family: "Arial"
|
||||
font.pixelSize: 16
|
||||
|
||||
color: "#4A4646"
|
||||
wrapMode: Text.Wrap
|
||||
text: qsTr("Custom daemon address (optional)")
|
||||
+ translationManager.emptyString
|
||||
}
|
||||
columnSpacing: 20
|
||||
rowSpacing: 20
|
||||
flow: isMobile ? GridLayout.TopToBottom : GridLayout.LeftToRight
|
||||
|
||||
RowLayout {
|
||||
spacing: 20
|
||||
|
@ -294,6 +302,7 @@ Item {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -28,10 +28,13 @@
|
|||
|
||||
import moneroComponents.WalletManager 1.0
|
||||
import QtQuick 2.2
|
||||
import QtQuick.Layouts 1.1
|
||||
import "../components"
|
||||
import "utils.js" as Utils
|
||||
|
||||
Item {
|
||||
ColumnLayout {
|
||||
Layout.leftMargin: wizardLeftMargin
|
||||
Layout.rightMargin: wizardRightMargin
|
||||
|
||||
id: passwordPage
|
||||
opacity: 0
|
||||
|
@ -72,12 +75,9 @@ Item {
|
|||
passwordUI.confirmPassword = "";
|
||||
}
|
||||
|
||||
Row {
|
||||
RowLayout {
|
||||
id: dotsRow
|
||||
anchors.top: parent.top
|
||||
anchors.right: parent.right
|
||||
anchors.topMargin: 85
|
||||
spacing: 6
|
||||
Layout.alignment: Qt.AlignRight
|
||||
|
||||
ListModel {
|
||||
id: dotsModel
|
||||
|
@ -100,20 +100,12 @@ Item {
|
|||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
ColumnLayout {
|
||||
id: headerColumn
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.leftMargin: 16
|
||||
anchors.rightMargin: 16
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 74
|
||||
spacing: 24
|
||||
|
||||
Text {
|
||||
Layout.fillWidth: true
|
||||
id: titleText
|
||||
anchors.left: parent.left
|
||||
width: headerColumn.width - dotsRow.width - 16
|
||||
font.family: "Arial"
|
||||
font.pixelSize: 28
|
||||
wrapMode: Text.Wrap
|
||||
|
@ -124,8 +116,8 @@ Item {
|
|||
}
|
||||
|
||||
Text {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
Layout.fillWidth: true
|
||||
Layout.bottomMargin: 30
|
||||
font.family: "Arial"
|
||||
font.pixelSize: 18
|
||||
wrapMode: Text.Wrap
|
||||
|
@ -138,15 +130,14 @@ Item {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
WizardPasswordUI {
|
||||
id: passwordUI
|
||||
anchors.right: parent.right
|
||||
anchors.left: parent.left
|
||||
anchors.top: headerColumn.bottom
|
||||
anchors.topMargin: 30
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true;
|
||||
WizardPasswordUI {
|
||||
id: passwordUI
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Component.onCompleted: {
|
||||
parent.wizardRestarted.connect(onWizardRestarted)
|
||||
}
|
||||
|
|
|
@ -29,21 +29,20 @@
|
|||
import QtQuick 2.0
|
||||
import QtQuick.Controls 1.4
|
||||
import QtQuick.Controls.Styles 1.4
|
||||
import QtQuick.Layouts 1.1
|
||||
|
||||
FocusScope {
|
||||
ColumnLayout {
|
||||
property alias password: password.text
|
||||
property alias placeholderText: password.placeholderText
|
||||
signal changed(string password)
|
||||
|
||||
|
||||
TextField {
|
||||
Layout.fillWidth: true
|
||||
id : password
|
||||
focus:true
|
||||
anchors.fill: parent
|
||||
horizontalAlignment: TextInput.AlignLeft
|
||||
verticalAlignment: TextInput.AlignVCenter
|
||||
font.family: "Arial"
|
||||
font.pixelSize: 32
|
||||
font.pixelSize: (isMobile) ? 25 : 32
|
||||
echoMode: TextInput.Password
|
||||
style: TextFieldStyle {
|
||||
renderType: Text.NativeRendering
|
||||
|
@ -62,9 +61,7 @@ FocusScope {
|
|||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
Layout.fillWidth:true
|
||||
height: 1
|
||||
color: "#DBDBDB"
|
||||
}
|
||||
|
|
|
@ -28,10 +28,11 @@
|
|||
|
||||
import moneroComponents.WalletManager 1.0
|
||||
import QtQuick 2.2
|
||||
import QtQuick.Layouts 1.1
|
||||
import "../components"
|
||||
import "utils.js" as Utils
|
||||
|
||||
FocusScope {
|
||||
ColumnLayout {
|
||||
property alias password: passwordItem.password
|
||||
property alias confirmPassword: retypePasswordItem.password
|
||||
property bool passwordsMatch: passwordItem.password === retypePasswordItem.password
|
||||
|
@ -62,10 +63,10 @@ FocusScope {
|
|||
|
||||
WizardPasswordInput {
|
||||
id: passwordItem
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.topMargin: 24
|
||||
width: 300
|
||||
height: 62
|
||||
Layout.fillWidth: true
|
||||
Layout.maximumWidth: 300
|
||||
Layout.minimumWidth: 200
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
placeholderText : qsTr("Password") + translationManager.emptyString;
|
||||
KeyNavigation.tab: retypePasswordItem
|
||||
onChanged: handlePassword()
|
||||
|
@ -74,22 +75,19 @@ FocusScope {
|
|||
|
||||
WizardPasswordInput {
|
||||
id: retypePasswordItem
|
||||
anchors.top: passwordItem.bottom
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.topMargin: 24
|
||||
width: 300
|
||||
height: 62
|
||||
Layout.fillWidth: true
|
||||
Layout.maximumWidth: 300
|
||||
Layout.minimumWidth: 200
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
placeholderText : qsTr("Confirm password") + translationManager.emptyString;
|
||||
KeyNavigation.tab: passwordItem
|
||||
onChanged: handlePassword()
|
||||
}
|
||||
|
||||
PrivacyLevelSmall {
|
||||
Layout.topMargin: isMobile ? 20 : 40
|
||||
Layout.fillWidth: true
|
||||
id: privacyLevel
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: retypePasswordItem.bottom
|
||||
anchors.topMargin: 60
|
||||
background: "#F0EEEE"
|
||||
interactive: false
|
||||
}
|
||||
|
|
|
@ -29,9 +29,10 @@
|
|||
import QtQuick 2.2
|
||||
import QtQuick.Dialogs 1.2
|
||||
import moneroComponents.Wallet 1.0
|
||||
import QtQuick.Layouts 1.1
|
||||
import 'utils.js' as Utils
|
||||
|
||||
Item {
|
||||
ColumnLayout {
|
||||
opacity: 0
|
||||
visible: false
|
||||
|
||||
|
@ -109,7 +110,6 @@ Item {
|
|||
id: uiItem
|
||||
accountNameText: defaultAccountName
|
||||
titleText: qsTr("Restore wallet") + translationManager.emptyString
|
||||
wordsTextTitle: qsTr("Enter your 25 word mnemonic seed:") + translationManager.emptyString
|
||||
wordsTextItem.clipboardButtonVisible: false
|
||||
wordsTextItem.tipTextVisible: false
|
||||
wordsTextItem.memoTextReadOnly: false
|
||||
|
|
|
@ -32,7 +32,9 @@ import QtQuick.Layouts 1.1
|
|||
import QtQml 2.2
|
||||
|
||||
|
||||
Item {
|
||||
|
||||
ColumnLayout {
|
||||
// anchors.fill:parent
|
||||
Behavior on opacity {
|
||||
NumberAnimation { duration: 100; easing.type: Easing.InQuad }
|
||||
}
|
||||
|
@ -60,45 +62,35 @@ Item {
|
|||
return true
|
||||
}
|
||||
|
||||
// Welcome text
|
||||
Column {
|
||||
ColumnLayout {
|
||||
id: headerColumn
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 74
|
||||
anchors.leftMargin: 16
|
||||
anchors.rightMargin: 16
|
||||
spacing: 24
|
||||
Layout.leftMargin: wizardLeftMargin
|
||||
Layout.rightMargin: wizardRightMargin
|
||||
Layout.bottomMargin: 40
|
||||
spacing: 20
|
||||
|
||||
Text {
|
||||
id: welcomeText
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
Layout.fillWidth: true
|
||||
font.family: "Arial"
|
||||
font.pixelSize: 28
|
||||
//renderType: Text.NativeRendering
|
||||
color: "#3F3F3F"
|
||||
wrapMode: Text.Wrap
|
||||
// hack to implement dynamic translation
|
||||
// https://wiki.qt.io/How_to_do_dynamic_translation_in_QML
|
||||
text: qsTr("Welcome") +
|
||||
translationManager.emptyString
|
||||
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
text: qsTr("Welcome to Monero!") + translationManager.emptyString
|
||||
}
|
||||
|
||||
Text {
|
||||
id: selectLanguageText
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
Layout.fillWidth: true
|
||||
font.family: "Arial"
|
||||
font.pixelSize: 18
|
||||
//renderType: Text.NativeRendering
|
||||
color: "#4A4646"
|
||||
wrapMode: Text.Wrap
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
text: qsTr("Please choose a language and regional format.") + translationManager.emptyString
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Flags model
|
||||
XmlListModel {
|
||||
id: languagesModel
|
||||
|
@ -124,63 +116,72 @@ Item {
|
|||
}
|
||||
}
|
||||
|
||||
// Flags view
|
||||
GridView {
|
||||
id: gridView
|
||||
cellWidth: 140
|
||||
cellHeight: 120
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.top: headerColumn.bottom
|
||||
anchors.topMargin: 24
|
||||
anchors.leftMargin: 16
|
||||
anchors.rightMargin: 16
|
||||
clip: true
|
||||
model: languagesModel
|
||||
ColumnLayout{
|
||||
// Flags view
|
||||
GridView {
|
||||
property int margin: (isMobile) ? 0 : Math.floor(appWindow.width/12);
|
||||
|
||||
delegate: Item {
|
||||
id: flagDelegate
|
||||
width: gridView.cellWidth
|
||||
height: gridView.cellHeight
|
||||
id: gridView
|
||||
cellWidth: 140
|
||||
cellHeight: 120
|
||||
model: languagesModel
|
||||
// Hack to center the flag grid
|
||||
property int columns: Math.floor(appWindow.width/140)
|
||||
Layout.leftMargin: margin + (appWindow.width - cellWidth*columns) /2
|
||||
Layout.rightMargin: margin
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
Rectangle {
|
||||
id: flagRect
|
||||
width: 60; height: 60
|
||||
anchors.centerIn: parent
|
||||
radius: 30
|
||||
color: gridView.currentIndex === index ? "#DBDBDB" : "#FFFFFF"
|
||||
Image {
|
||||
anchors.fill: parent
|
||||
source: flag
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
font.family: "Arial"
|
||||
font.pixelSize: 18
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.top: flagRect.bottom
|
||||
anchors.topMargin: 10
|
||||
font.bold: gridView.currentIndex === index
|
||||
elide: Text.ElideRight
|
||||
color: "#3F3F3F"
|
||||
text: display_name
|
||||
}
|
||||
MouseArea {
|
||||
id: delegateArea
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
gridView.currentIndex = index
|
||||
var data = languagesModel.get(gridView.currentIndex);
|
||||
if (data !== null || data !== undefined) {
|
||||
var locale = data.locale
|
||||
translationManager.setLanguage(locale.split("_")[0]);
|
||||
wizard.switchPage(true)
|
||||
clip: true
|
||||
|
||||
delegate: ColumnLayout {
|
||||
id: flagDelegate
|
||||
width: gridView.cellWidth
|
||||
// height: gridView.cellHeight
|
||||
// Layout.alignment: Qt.AlignHCenter
|
||||
Rectangle {
|
||||
id: flagRect
|
||||
width: 60; height: 60
|
||||
// anchors.centerIn: parent
|
||||
radius: 30
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
color: gridView.currentIndex === index ? "#DBDBDB" : "#FFFFFF"
|
||||
Image {
|
||||
anchors.fill: parent
|
||||
source: flag
|
||||
}
|
||||
}
|
||||
}
|
||||
} // delegate
|
||||
|
||||
Text {
|
||||
font.family: "Arial"
|
||||
font.pixelSize: 18
|
||||
// anchors.horizontalCenter: parent.horizontalCenter
|
||||
font.bold: gridView.currentIndex === index
|
||||
// elide: Text.ElideRight
|
||||
color: "#3F3F3F"
|
||||
text: display_name
|
||||
// horizontalAlignment: Text.AlignHCenter
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
}
|
||||
MouseArea {
|
||||
id: delegateArea
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
gridView.currentIndex = index
|
||||
var data = languagesModel.get(gridView.currentIndex);
|
||||
if (data !== null || data !== undefined) {
|
||||
var locale = data.locale
|
||||
translationManager.setLanguage(locale.split("_")[0]);
|
||||
wizard.switchPage(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
} // delegate
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue