Browse Source

Merge branch 'seed_keyboard'

master
Sander van Grieken 3 years ago
parent
commit
1a889d19b5
  1. 4
      electrum/gui/qml/__init__.py
  2. 93
      electrum/gui/qml/components/controls/SeedKeyboard.qml
  3. 43
      electrum/gui/qml/components/controls/SeedKeyboardKey.qml
  4. 92
      electrum/gui/qml/components/controls/SeedTextArea.qml
  5. 54
      electrum/gui/qml/components/main.qml
  6. 2
      electrum/gui/qml/components/wizard/WCConfirmSeed.qml
  7. 23
      electrum/gui/qml/components/wizard/WCHaveSeed.qml

4
electrum/gui/qml/__init__.py

@ -61,10 +61,6 @@ class ElectrumGui(BaseElectrumGui, Logger):
# os.environ['QML_IMPORT_TRACE'] = '1'
# os.environ['QT_DEBUG_PLUGINS'] = '1'
os.environ['QT_IM_MODULE'] = 'qtvirtualkeyboard'
os.environ['QT_VIRTUALKEYBOARD_STYLE'] = 'Electrum'
os.environ['QML2_IMPORT_PATH'] = 'electrum/gui/qml'
os.environ['QT_ANDROID_DISABLE_ACCESSIBILITY'] = '1'
# set default locale to en_GB. This is for l10n (e.g. number formatting, number input etc),

93
electrum/gui/qml/components/controls/SeedKeyboard.qml

@ -0,0 +1,93 @@
import QtQuick 2.15
import QtQuick.Layouts 1.0
import QtQuick.Controls 2.15
import QtQuick.Controls.Material 2.0
Item {
id: root
signal keyEvent(keycode: int, text: string)
property int hpadding: 0
property int vpadding: 15
property int keywidth: (root.width - 2 * hpadding) / 10 - keyhspacing
property int keyheight: (root.height - 2 * vpadding) / 4 - keyvspacing
property int keyhspacing: 4
property int keyvspacing: 5
function emitKeyEvent(key, keycode) {
keyEvent(keycode, key)
}
ColumnLayout {
id: rootLayout
x: hpadding
y: vpadding
width: parent.width - 2*hpadding
spacing: keyvspacing
RowLayout {
Layout.alignment: Qt.AlignHCenter
spacing: keyhspacing
Repeater {
model: ['q','w','e','r','t','y','u','i','o','p']
delegate: SeedKeyboardKey {
key: modelData
kbd: root
implicitWidth: keywidth
implicitHeight: keyheight
}
}
}
RowLayout {
Layout.alignment: Qt.AlignHCenter
spacing: keyhspacing
Repeater {
model: ['a','s','d','f','g','h','j','k','l']
delegate: SeedKeyboardKey {
key: modelData
kbd: root
implicitWidth: keywidth
implicitHeight: keyheight
}
}
// spacer
Item { Layout.preferredHeight: 1; Layout.preferredWidth: keywidth / 2 }
}
RowLayout {
Layout.alignment: Qt.AlignHCenter
spacing: keyhspacing
Repeater {
model: ['z','x','c','v','b','n','m']
delegate: SeedKeyboardKey {
key: modelData
kbd: root
implicitWidth: keywidth
implicitHeight: keyheight
}
}
// spacer
Item { Layout.preferredHeight: 1; Layout.preferredWidth: keywidth }
}
RowLayout {
Layout.alignment: Qt.AlignHCenter
SeedKeyboardKey {
key: ' '
keycode: Qt.Key_Space
kbd: root
implicitWidth: keywidth * 5
implicitHeight: keyheight
}
SeedKeyboardKey {
key: '<'
keycode: Qt.Key_Backspace
kbd: root
implicitWidth: keywidth
implicitHeight: keyheight
}
// spacer
Item { Layout.preferredHeight: 1; Layout.preferredWidth: keywidth / 2 }
}
}
}

43
electrum/gui/qml/components/controls/SeedKeyboardKey.qml

@ -0,0 +1,43 @@
import QtQuick 2.15
import QtQuick.Layouts 1.0
import QtQuick.Controls 2.15
import QtQuick.Controls.Material 2.0
Pane {
id: root
property string key
property int keycode: -1
property QtObject kbd
padding: 1
function emitKeyEvent() {
if (keycode == -1) {
keycode = parseInt(key, 36) - 9 + 0x40 // map a-z char to key code
}
kbd.keyEvent(keycode, key)
}
FlatButton {
anchors.fill: parent
focusPolicy: Qt.NoFocus
autoRepeat: true
autoRepeatDelay: 750
text: key
padding: 0
font.pixelSize: Math.max(root.height * 1/3, constants.fontSizeSmall)
onClicked: {
emitKeyEvent()
}
// send keyevent again, otherwise it is ignored
onDoubleClicked: {
emitKeyEvent()
}
}
}

92
electrum/gui/qml/components/controls/SeedTextArea.qml

@ -11,8 +11,10 @@ Pane {
padding: 0
property string text
property alias readOnly: seedtextarea.readOnly
property bool readOnly: false
property alias placeholderText: seedtextarea.placeholderText
property string indicatorText
property bool indicatorValid
property var _suggestions: []
@ -29,6 +31,56 @@ Pane {
id: rootLayout
width: parent.width
spacing: 0
TextArea {
id: seedtextarea
Layout.fillWidth: true
Layout.minimumHeight: fontMetrics.height * 3 + topPadding + bottomPadding
rightPadding: constants.paddingLarge
leftPadding: constants.paddingLarge
wrapMode: TextInput.WordWrap
font.bold: true
font.pixelSize: constants.fontSizeLarge
font.family: FixedFont
inputMethodHints: Qt.ImhSensitiveData | Qt.ImhLowercaseOnly | Qt.ImhNoPredictiveText
readOnly: true
background: Rectangle {
color: constants.darkerBackground
}
onTextChanged: {
// work around Qt issue, TextArea fires spurious textChanged events
// NOTE: might be Qt virtual keyboard, or Qt upgrade from 5.15.2 to 5.15.7
if (root.text != text)
root.text = text
// update suggestions
_suggestions = bitcoin.mnemonicsFor(seedtextarea.text.split(' ').pop())
// TODO: cursorPosition only on suggestion apply
cursorPosition = text.length
}
Rectangle {
anchors.fill: contentText
color: root.indicatorValid ? 'green' : 'red'
border.color: Material.accentColor
radius: 2
}
Label {
id: contentText
text: root.indicatorText
anchors.right: parent.right
anchors.bottom: parent.bottom
leftPadding: root.indicatorText != '' ? constants.paddingLarge : 0
rightPadding: root.indicatorText != '' ? constants.paddingLarge : 0
font.bold: false
font.pixelSize: constants.fontSizeSmall
}
}
Flickable {
Layout.preferredWidth: parent.width
Layout.minimumHeight: fontMetrics.lineSpacing + 2*constants.paddingXXSmall + 2*constants.paddingXSmall + 2
@ -70,34 +122,18 @@ Pane {
}
}
TextArea {
id: seedtextarea
SeedKeyboard {
id: kbd
Layout.fillWidth: true
Layout.minimumHeight: fontMetrics.height * 3 + topPadding + bottomPadding
rightPadding: constants.paddingLarge
leftPadding: constants.paddingLarge
wrapMode: TextInput.WordWrap
font.bold: true
font.pixelSize: constants.fontSizeLarge
font.family: FixedFont
inputMethodHints: Qt.ImhSensitiveData | Qt.ImhLowercaseOnly | Qt.ImhNoPredictiveText
background: Rectangle {
color: constants.darkerBackground
}
onTextChanged: {
// work around Qt issue, TextArea fires spurious textChanged events
// NOTE: might be Qt virtual keyboard, or Qt upgrade from 5.15.2 to 5.15.7
if (root.text != text)
root.text = text
// update suggestions
_suggestions = bitcoin.mnemonicsFor(seedtextarea.text.split(' ').pop())
// TODO: cursorPosition only on suggestion apply
cursorPosition = text.length
Layout.preferredHeight: kbd.width / 2
visible: !root.readOnly
onKeyEvent: {
if (keycode == Qt.Key_Backspace) {
if (seedtextarea.text.length > 0)
seedtextarea.text = seedtextarea.text.substring(0, seedtextarea.text.length-1)
} else {
seedtextarea.text = seedtextarea.text + text
}
}
}
}

54
electrum/gui/qml/components/main.qml

@ -3,6 +3,7 @@ import QtQuick.Layouts 1.0
import QtQuick.Controls 2.3
import QtQuick.Controls.Material 2.0
import QtQuick.Controls.Material.impl 2.12
import QtQuick.Window 2.15
import QtQml 2.6
import QtMultimedia 5.6
@ -31,7 +32,6 @@ ApplicationWindow
Constants { id: appconstants }
property alias stack: mainStackView
property alias inputPanel: inputPanel
property variant activeDialogs: []
@ -224,7 +224,7 @@ ApplicationWindow
StackView {
id: mainStackView
width: parent.width
height: inputPanel.y - header.height
height: keyboardFreeZone.height - header.height
initialItem: Qt.resolvedUrl('WalletMainView.qml')
function getRoot() {
@ -266,39 +266,47 @@ ApplicationWindow
}
Item {
id: keyboardFreeZone
// Item as first child in Overlay that adjusts its size to the available
// screen space minus the virtual keyboard (e.g. to center dialogs in)
// see ElDialog.resizeWithKeyboard property
// see also ElDialog.resizeWithKeyboard property
parent: Overlay.overlay
width: parent.width
height: inputPanel.y
}
InputPanel {
id: inputPanel
width: parent.width
y: parent.height
height: parent.height
states: State {
name: "visible"
when: inputPanel.active
when: Qt.inputMethod.visible
PropertyChanges {
target: inputPanel
y: parent.height - height
target: keyboardFreeZone
height: keyboardFreeZone.parent.height - Qt.inputMethod.keyboardRectangle.height / Screen.devicePixelRatio
}
}
transitions: Transition {
from: ''
to: 'visible'
reversible: true
ParallelAnimation {
NumberAnimation {
properties: "y"
duration: 250
easing.type: Easing.OutQuad
transitions: [
Transition {
from: ''
to: 'visible'
ParallelAnimation {
NumberAnimation {
properties: "height"
duration: 250
easing.type: Easing.OutQuad
}
}
},
Transition {
from: 'visible'
to: ''
ParallelAnimation {
NumberAnimation {
properties: "height"
duration: 50
easing.type: Easing.OutQuad
}
}
}
}
]
}
property alias newWalletWizard: _newWalletWizard

2
electrum/gui/qml/components/wizard/WCConfirmSeed.qml

@ -30,13 +30,13 @@ WizardComponent {
InfoTextArea {
Layout.fillWidth: true
Layout.bottomMargin: constants.paddingLarge
text: qsTr('Your seed is important!') + ' ' +
qsTr('If you lose your seed, your money will be permanently lost.') + ' ' +
qsTr('To make sure that you have properly saved your seed, please retype it here.')
}
Label {
Layout.topMargin: constants.paddingMedium
text: qsTr('Confirm your seed (re-enter)')
}

23
electrum/gui/qml/components/wizard/WCHaveSeed.qml

@ -164,6 +164,7 @@ WizardComponent {
id: infotext
Layout.fillWidth: true
Layout.columnSpan: 2
Layout.bottomMargin: constants.paddingLarge
}
SeedTextArea {
@ -173,25 +174,11 @@ WizardComponent {
placeholderText: cosigner ? qsTr('Enter cosigner seed') : qsTr('Enter your seed')
indicatorValid: root.valid
onTextChanged: {
startValidationTimer()
}
Rectangle {
anchors.fill: contentText
color: root.valid ? 'green' : 'red'
border.color: Material.accentColor
radius: 2
}
Label {
id: contentText
anchors.right: parent.right
anchors.bottom: parent.bottom
leftPadding: text != '' ? constants.paddingLarge : 0
rightPadding: text != '' ? constants.paddingLarge : 0
font.bold: false
font.pixelSize: constants.fontSizeSmall
}
}
TextArea {
id: validationtext
@ -223,13 +210,13 @@ WizardComponent {
Bitcoin {
id: bitcoin
onSeedTypeChanged: contentText.text = bitcoin.seedType
onSeedTypeChanged: seedtext.indicatorText = bitcoin.seedType
onValidationMessageChanged: validationtext.text = validationMessage
}
function startValidationTimer() {
valid = false
contentText.text = ''
seedtext.indicatorText = ''
validationTimer.restart()
}

Loading…
Cancel
Save