Merge pull request #10485 from accumulator/ndk28_qt610_rebase_p4a

p4a rebase, use ndk28 and qt6.10
This commit is contained in:
ghost43
2026-04-24 17:06:25 +00:00
committed by GitHub
107 changed files with 886 additions and 923 deletions
+15 -30
View File
@@ -33,12 +33,8 @@ RUN apt -y update -qq \
ENV ANDROID_NDK_HOME="${ANDROID_HOME}/android-ndk"
#ENV ANDROID_NDK_VERSION="23b"
#ENV ANDROID_NDK_HASH="c6e97f9c8cfe5b7be0a9e6c15af8e7a179475b7ded23e2d1c1fa0945d6fb4382"
#ENV ANDROID_NDK_VERSION="27d"
#ENV ANDROID_NDK_HASH="601246087a682d1944e1e16dd85bc6e49560fe8b6d61255be2829178c8ed15d9"
ENV ANDROID_NDK_VERSION="23d-canary"
ENV ANDROID_NDK_HASH="6944ffc20ab018ff4ef6a403048d0a99d50a0630c3eae690c8f803c452f46f3e"
ENV ANDROID_NDK_VERSION="28c"
ENV ANDROID_NDK_HASH="dfb20d396df28ca02a8c708314b814a4d961dc9074f9a161932746f815aa552f"
ENV ANDROID_NDK_HOME_V="${ANDROID_NDK_HOME}-r${ANDROID_NDK_VERSION}"
# get the latest version from https://developer.android.com/ndk/downloads/index.html
@@ -48,31 +44,21 @@ ENV ANDROID_NDK_DL_URL="https://dl.google.com/android/repository/${ANDROID_NDK_A
# below disabled in favor of CI build download
# download and install Android NDK
#RUN curl --location --progress-bar \
# "${ANDROID_NDK_DL_URL}" \
# --output "${ANDROID_NDK_ARCHIVE}" \
# && echo "${ANDROID_NDK_HASH} ${ANDROID_NDK_ARCHIVE}" | sha256sum -c - \
# && mkdir --parents "${ANDROID_NDK_HOME_V}" \
# && unzip -q "${ANDROID_NDK_ARCHIVE}" -d "${ANDROID_HOME}" \
# && ln -sfn "${ANDROID_NDK_HOME_V}" "${ANDROID_NDK_HOME}" \
# && rm -rf "${ANDROID_NDK_ARCHIVE}"
# temporary build using NDK from CI
ENV CI_REV="12186248"
ENV CI_NDK_FILE="android-ndk-${CI_REV}-linux-x86_64.zip"
COPY contrib/android/dl-ndk-ci.sh /tmp/
RUN /tmp/dl-ndk-ci.sh https://ci.android.com/builds/submitted/${CI_REV}/linux/latest/${CI_NDK_FILE} \
&& echo "${ANDROID_NDK_HASH} android-ndk-ci-linux-x86_64.zip" | sha256sum -c - \
RUN curl --location --progress-bar \
"${ANDROID_NDK_DL_URL}" \
--output "${ANDROID_NDK_ARCHIVE}" \
&& echo "${ANDROID_NDK_HASH} ${ANDROID_NDK_ARCHIVE}" | sha256sum -c - \
&& mkdir --parents "${ANDROID_NDK_HOME_V}" \
&& unzip -q "android-ndk-ci-linux-x86_64.zip" -d "${ANDROID_HOME}" \
&& unzip -q "${ANDROID_NDK_ARCHIVE}" -d "${ANDROID_HOME}" \
&& ln -sfn "${ANDROID_NDK_HOME_V}" "${ANDROID_NDK_HOME}" \
&& rm -rf "android-ndk-ci-linux-x86_64.zip"
&& rm -rf "${ANDROID_NDK_ARCHIVE}"
ENV ANDROID_SDK_HOME="${ANDROID_HOME}/android-sdk"
# get the latest version from https://developer.android.com/studio/index.html
ENV ANDROID_SDK_TOOLS_VERSION="9477386"
ENV ANDROID_SDK_HASH="bd1aa17c7ef10066949c88dc6c9c8d536be27f992a1f3b5a584f9bd2ba5646a0"
ENV ANDROID_SDK_TOOLS_VERSION="14742923"
ENV ANDROID_SDK_HASH="04453066b540409d975c676d781da1477479dde3761310f1a7eb92a1dfb15af7"
ENV ANDROID_SDK_TOOLS_ARCHIVE="commandlinetools-linux-${ANDROID_SDK_TOOLS_VERSION}_latest.zip"
ENV ANDROID_SDK_TOOLS_DL_URL="https://dl.google.com/android/repository/${ANDROID_SDK_TOOLS_ARCHIVE}"
ENV ANDROID_SDK_MANAGER="${ANDROID_SDK_HOME}/cmdline-tools/bin/sdkmanager --sdk_root=${ANDROID_SDK_HOME}"
@@ -130,8 +116,8 @@ RUN apt -y update -qq \
RUN yes | ${ANDROID_SDK_MANAGER} --licenses > /dev/null
ENV ANDROID_SDK_BUILD_TOOLS_MAJOR_V="31"
ENV ANDROID_SDK_BUILD_TOOLS_VERSION="31.0.0"
ENV ANDROID_SDK_BUILD_TOOLS_MAJOR_V="35"
ENV ANDROID_SDK_BUILD_TOOLS_VERSION="35.0.0"
# download platforms, API, build tools
RUN ${ANDROID_SDK_MANAGER} "platforms;android-${ANDROID_SDK_BUILD_TOOLS_MAJOR_V}" > /dev/null && \
@@ -190,7 +176,6 @@ RUN apt -y update -qq \
&& apt -y install -qq --no-install-recommends --allow-downgrades \
libopengl-dev \
libegl-dev \
dos2unix \
&& apt -y autoremove \
&& apt -y clean
@@ -250,8 +235,8 @@ RUN cd /opt \
&& /opt/venv/bin/python3 -m pip install --no-build-isolation --no-dependencies -e .
# install python-for-android
ENV P4A_CHECKOUT_COMMIT="a01269f7799587ad74ee40e0b642d917b8db7d4e"
# ^ from branch electrum_20251211 (note: careful with force-pushing! see #8162)
ENV P4A_CHECKOUT_COMMIT="1098be6964cfc2156959e435e81c2c50f8398586"
# ^ from branch electrum_202602 (note: careful with force-pushing! see #8162)
RUN cd /opt \
&& git clone https://github.com/spesmilo/python-for-android \
&& cd python-for-android \
-2
View File
@@ -108,8 +108,6 @@ Run electrum with the `-g` switch: `electrum -g qml`
Notes:
- pyqt ~6.4 would work best, as the gui has not yet been adapted to styling changes in 6.5
- However, pyqt6 as distributed on PyPI does not include a required module (PyQt6.QtQml) until 6.5
- Installing these deps from your OS package manager should also work,
except many don't distribute pyqt6 yet.
For pyqt5 on debian-based distros, this used to look like this:
+5 -5
View File
@@ -105,19 +105,19 @@ android.permissions = INTERNET, CAMERA, WRITE_EXTERNAL_STORAGE, POST_NOTIFICATIO
# (int) Android API to use (compileSdkVersion)
# note: when changing, Dockerfile also needs to be changed to install corresponding build tools
android.api = 31
android.api = 35
# (int) Android targetSdkVersion
android.target_sdk_version = 35
# (int) Minimum API required. You will need to set the android.ndk_api to be as low as this value.
android.minapi = 23
android.minapi = 26
# (str) Android NDK version to use
android.ndk = 23b
android.ndk = 28c
# (int) Android NDK API to use (optional). This is the minimum API your app will support.
android.ndk_api = 23
android.ndk_api = 26
# (bool) Use --private data storage (True) or --dir public storage (False)
#android.private_storage = True
@@ -168,7 +168,7 @@ android.add_src = electrum/gui/qml/java_classes/
# kotlin-stdlib is required for zxing-cpp (BarcodeScannerView)
android.gradle_dependencies =
com.android.support:support-compat:28.0.0,
androidx.core:core:1.16.0,
org.jetbrains.kotlin:kotlin-stdlib:1.8.22
android.add_activities = org.electrum.qr.SimpleScannerActivity, org.electrum.biometry.BiometricActivity
-8
View File
@@ -1,8 +0,0 @@
#!/bin/sh
if [ -z "$1" ]; then
echo "missing url"
exit 1
fi
echo $1
curl $1 | grep "var JSVariables" | python3 -c "import sys; line=sys.stdin.read(); line=line[line.find('{'):-2]; import json; j=json.loads(line); print(j['artifactUrl'])" | wget -i - -O android-ndk-ci-linux-x86_64.zip
@@ -0,0 +1,20 @@
import os
from pythonforandroid.recipes.android import AndroidRecipe
from pythonforandroid.util import load_source, HashPinnedDependency
util = load_source('util', os.path.join(os.path.dirname(os.path.dirname(__file__)), 'util.py'))
assert AndroidRecipe.depends == [('sdl3', 'sdl2', 'genericndkbuild', 'qt6'), 'pyjnius', 'python3'], AndroidRecipe.depends
assert AndroidRecipe.python_depends == []
class AndroidRecipePinned(util.InheritedRecipeMixin, AndroidRecipe):
hostpython_prerequisites = [
HashPinnedDependency(package="Cython==3.1.8",
hashes=['sha256:282b3c8e6abc3fea421919e862e898ffdd86fc0796009bdb5ffdf8211413219f'])
]
recipe = AndroidRecipePinned()
+3 -4
View File
@@ -6,14 +6,13 @@ from pythonforandroid.util import load_source
util = load_source('util', os.path.join(os.path.dirname(os.path.dirname(__file__)), 'util.py'))
assert CffiRecipe._version == "1.15.1"
assert CffiRecipe.depends == ['setuptools', 'pycparser', 'libffi', 'python3']
assert CffiRecipe._version == "2.0.0"
assert CffiRecipe.depends == ['pycparser', 'libffi', 'python3'], CffiRecipe.depends
assert CffiRecipe.python_depends == []
class CffiRecipePinned(util.InheritedRecipeMixin, CffiRecipe):
version = "1.17.1"
sha512sum = "907129891d56351ca5cb885aae62334ad432321826d6eddfaa32195b4c7b7689a80333e6d14d0aab479a646aba148b9852c0815b80344dfffa4f183a5e74372c"
sha512sum = "a71b74e642e11eb50e9bb4ae0e7116bdb3c4a7c9622a3766d84506fa7994c02e09644b41b439b95ca99b0303e91891897cff38018d498eb087e0961f0ad4fb8b"
recipe = CffiRecipePinned()
@@ -1,7 +1,7 @@
import os
from pythonforandroid.recipes.hostpython3 import HostPython3Recipe
from pythonforandroid.util import load_source
from pythonforandroid.util import load_source, HashPinnedDependency
util = load_source('util', os.path.join(os.path.dirname(os.path.dirname(__file__)), 'util.py'))
@@ -13,7 +13,23 @@ assert HostPython3Recipe.python_depends == []
class HostPython3RecipePinned(util.InheritedRecipeMixin, HostPython3Recipe):
# PYTHON_VERSION= # < line here so that I can grep the codebase and teleport here
version = "3.11.14"
sha512sum = "41fb3ae22ce4ac0e8bb6b9ae8db88a810af1001d944e3f1abc9e86824ae4be31347e3e3a70425ab12271c6b7eeef552f00164ef23cfffa2551c3c9d1fe5ab91f"
sha512sum = "4642f6d59c76c6e5dbd827fdb28694376a9cc76e513146d092b49afb41513b3c9dff2339cfcebfb5b260f5cdc49a59a69906e284e5d478b2189d3374e9e24fd5"
# this property overrides the default hostpython dependencies for PyProjectRecipe recipies
pyproject_base_dependencies = [
HashPinnedDependency(package="build==1.4.0",
hashes=['sha256:6a07c1b8eb6f2b311b96fcbdbce5dab5fe637ffda0fd83c9cac622e927501596']),
HashPinnedDependency(package="pip==24.0",
hashes=['sha256:ba0d021a166865d2265246961bec0152ff124de910c5cc39f1156ce3fa7c69dc']),
HashPinnedDependency(package="setuptools==80.9.0",
hashes=['sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922']),
# pin deptree build==1.4.0
HashPinnedDependency(package="packaging==26.0",
hashes=['sha256:b36f1fef9334a5588b4166f8bcd26a14e521f2b55e6b9de3aaa80d3ff7a37529']),
HashPinnedDependency(package="pyproject_hooks==1.2.0",
hashes=['sha256:9e5c6bfa8dcc30091c74b0cf803c81fdd29d94f01992a7707bc97babb1141913']),
]
recipe = HostPython3RecipePinned()
@@ -6,7 +6,7 @@ from pythonforandroid.util import load_source
util = load_source('util', os.path.join(os.path.dirname(os.path.dirname(__file__)), 'util.py'))
assert OpenSSLRecipe._version == "3.0.18"
# assert OpenSSLRecipe._version == "3.3.1"
assert OpenSSLRecipe.depends == []
assert OpenSSLRecipe.python_depends == []
@@ -1,15 +1,13 @@
from pythonforandroid.recipes.packaging import PackagingRecipe
assert PackagingRecipe._version == "21.3"
assert PackagingRecipe._version == "26.0"
assert PackagingRecipe.depends == ["setuptools", "pyparsing", "python3"]
assert PackagingRecipe.python_depends == []
class PackagingRecipePinned(PackagingRecipe):
#version = "21.3"
# note: 21.3 is the last version to use setup.py, so newer versions don't work. see comment for PyparsingRecipePinned
sha512sum = "2e3aa276a4229ac7dc0654d586799473ced9761a83aa4159660d37ae1a2a8f30e987248dd0e260e2834106b589f259a57ce9936eef0dcc3c430a99ac6b663e05"
sha512sum = "27a066a7d65ba76189212973b6a0d162f3d361848b1b0c34a82865cf180b3284a837cc34206c297f002a73feae414e25a26c5960bb884a74ea337f582585f1d2"
recipe = PackagingRecipePinned()
@@ -1,5 +1,5 @@
from pythonforandroid.recipe import PythonRecipe
from pythonforandroid.util import HashPinnedDependency
assert PythonRecipe.depends == ['python3']
assert PythonRecipe.python_depends == []
@@ -9,7 +9,11 @@ class PycryptodomexRecipe(PythonRecipe):
version = "3.23.0"
sha512sum = "951cebaad2e19b9f9d04fe85c73ab1ff8b515069c1e0e8e3cd6845ec9ccd5ef3e5737259e0934ed4a6536e289dee6aabac58e1c822a5a6393e86b482c60afc89"
url = "https://github.com/Legrandin/pycryptodome/archive/v{version}x.tar.gz"
depends = ["setuptools", "cffi"]
depends = ["cffi"]
hostpython_prerequisites = [
HashPinnedDependency(package="setuptools==80.9.0",
hashes=['sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922']),
]
recipe = PycryptodomexRecipe()
@@ -1,19 +1,23 @@
import os
from pythonforandroid.recipes.pyjnius import PyjniusRecipe
from pythonforandroid.util import load_source
from pythonforandroid.util import load_source, HashPinnedDependency
util = load_source('util', os.path.join(os.path.dirname(os.path.dirname(__file__)), 'util.py'))
assert PyjniusRecipe._version == "1.5.0"
assert PyjniusRecipe.depends == [('genericndkbuild', 'sdl2', 'qt6'), 'six', 'python3']
assert PyjniusRecipe._version == "1.7.0"
assert PyjniusRecipe.depends == [('genericndkbuild', 'sdl2', 'sdl3', 'qt6'), 'six', 'python3'], PyjniusRecipe.depends
assert PyjniusRecipe.python_depends == []
class PyjniusRecipePinned(util.InheritedRecipeMixin, PyjniusRecipe):
version = "1.6.1"
sha512sum = "deb5ac566479111c6f4c6adb895821b263d72bf88414fb093bdfd5ad5d0b7aea56b53d5ef0967e28db360f4fb6fb1c2264123f15c747884799df55848191c424"
hostpython_prerequisites = [
HashPinnedDependency(package="Cython==3.1.8",
hashes=['sha256:282b3c8e6abc3fea421919e862e898ffdd86fc0796009bdb5ffdf8211413219f'])
]
sha512sum = "a192c30ef87ca9601455976feb49f03dfdb8e1bf2545744a7b771a6d0930a56b334c7a2a39d30fb8855c070f16e4673dc5ff6920b04a6155ab5f9247b271df76"
recipe = PyjniusRecipePinned()
@@ -1,4 +1,5 @@
from pythonforandroid.recipes.pyparsing import PyparsingRecipe
from pythonforandroid.util import HashPinnedDependency
assert PyparsingRecipe._version == "3.0.7"
@@ -15,5 +16,12 @@ class PyparsingRecipePinned(PyparsingRecipe):
# see "PyProjectRecipe" from https://github.com/kivy/python-for-android/pull/3007
sha512sum = "1e692f4cdaa6b6e8ca2729d0a3e2ba16d978f1957c538b6de3a4220ec7d996bdbe87c41c43abab851fffa3b0498a05841373e435602917b8c095042e273badb5"
hostpython_prerequisites = [
HashPinnedDependency(package="setuptools==80.9.0",
hashes=['sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922']),
HashPinnedDependency(package="pip==24.0",
hashes=['sha256:ba0d021a166865d2265246961bec0152ff124de910c5cc39f1156ce3fa7c69dc']),
]
recipe = PyparsingRecipePinned()
@@ -1,18 +1,18 @@
import os
from pythonforandroid.recipes.pyqt6 import PyQt6Recipe
from pythonforandroid.util import load_source
from pythonforandroid.util import load_source, HashPinnedDependency
util = load_source('util', os.path.join(os.path.dirname(os.path.dirname(__file__)), 'util.py'))
assert PyQt6Recipe._version == "6.4.2"
assert PyQt6Recipe.depends == ['qt6', 'pyjnius', 'setuptools', 'pyqt6sip', 'hostpython3', 'pyqt_builder']
assert PyQt6Recipe._version == "6.10.2"
assert PyQt6Recipe.depends == ['qt6', 'pyjnius', 'setuptools', 'pyqt6sip', 'hostpython3', 'pyqt_builder', 'python3'], PyQt6Recipe.depends
assert PyQt6Recipe.python_depends == []
class PyQt6RecipePinned(util.InheritedRecipeMixin, PyQt6Recipe):
sha512sum = "51e5f0d028ee7984876da1653cb135d61e2c402f18b939a92477888cc7c86d3bc2889477403dee6b3d9f66519ee3236d344323493b4c2c2e658e1637b10e53bf"
sha512sum = "d58515d181530fdd71edc3edfa0b647a3aeeb56cbc33f4d7fd0d40a7a99d52298ac5bb4438b5dadea5439759e52cc459e601f1fab5d9afdd61f2a492d0bae1ef"
recipe = PyQt6RecipePinned()
@@ -1,18 +1,25 @@
import os
from pythonforandroid.recipes.pyqt6sip import PyQt6SipRecipe
from pythonforandroid.util import load_source
from pythonforandroid.util import load_source, HashPinnedDependency
util = load_source('util', os.path.join(os.path.dirname(os.path.dirname(__file__)), 'util.py'))
assert PyQt6SipRecipe._version == "13.5.1"
assert PyQt6SipRecipe.depends == ['setuptools', 'python3']
assert PyQt6SipRecipe._version == "13.10.3"
assert PyQt6SipRecipe.depends == ['python3']
assert PyQt6SipRecipe.python_depends == []
class PyQt6SipRecipePinned(util.InheritedRecipeMixin, PyQt6SipRecipe):
sha512sum = "1e4170d167a326afe6df86e4a35e209299548054981cb2e5d56da234ef9db4d8594bcb05b6be363c3bc6252776ae9de63d589a3d9f33fba8250d39cdb5e9061a"
sha512sum = "555b061eec3db6a66388fae07de21f58d756f6f12b13e4ede729c3348d2c8997ac5a59d3006ee45c3a09b5cde673f579265fa254bc583a4ba721748cf8f3a617"
hostpython_prerequisites = [
HashPinnedDependency(package="setuptools==80.9.0",
hashes=['sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922']),
HashPinnedDependency(package="packaging==26.0",
hashes=['sha256:b36f1fef9334a5588b4166f8bcd26a14e521f2b55e6b9de3aaa80d3ff7a37529']),
]
recipe = PyQt6SipRecipePinned()
@@ -1,13 +1,14 @@
from pythonforandroid.recipes.pyqt_builder import PyQtBuilderRecipe
from pythonforandroid.util import HashPinnedDependency
assert PyQtBuilderRecipe._version == "1.15.1"
assert PyQtBuilderRecipe.depends == ["sip", "packaging", "python3"]
assert PyQtBuilderRecipe._version == "1.19.1"
assert PyQtBuilderRecipe.depends == ["sip", "python3"], PyQtBuilderRecipe.depends
assert PyQtBuilderRecipe.python_depends == []
class PyQtBuilderRecipePinned(PyQtBuilderRecipe):
sha512sum = "61ee73b6bb922c04739da60025ab50d35d345d2e298943305fcbd3926cda31d732cc5e5b0dbfc39f5eb85c0f0b091b8c3f5fee00dcc240d7849c5c4191c1368a"
sha512sum = "2308c51f93c37b1d13f312e4f2475d26b22d374ef284925fead9eab4aa89b994770431aca45170ac2154b4813fff151798f113f56d4cbf6c6e544fb463104a6d"
recipe = PyQtBuilderRecipePinned()
@@ -13,7 +13,7 @@ assert Python3Recipe.python_depends == []
class Python3RecipePinned(util.InheritedRecipeMixin, Python3Recipe):
# PYTHON_VERSION= # < line here so that I can grep the codebase and teleport here
version = "3.11.14"
sha512sum = "41fb3ae22ce4ac0e8bb6b9ae8db88a810af1001d944e3f1abc9e86824ae4be31347e3e3a70425ab12271c6b7eeef552f00164ef23cfffa2551c3c9d1fe5ab91f"
sha512sum = "4642f6d59c76c6e5dbd827fdb28694376a9cc76e513146d092b49afb41513b3c9dff2339cfcebfb5b260f5cdc49a59a69906e284e5d478b2189d3374e9e24fd5"
recipe = Python3RecipePinned()
+3 -5
View File
@@ -1,19 +1,17 @@
import os
from pythonforandroid.recipes.qt6 import Qt6Recipe
from pythonforandroid.util import load_source
util = load_source('util', os.path.join(os.path.dirname(os.path.dirname(__file__)), 'util.py'))
assert Qt6Recipe._version == "6.4.3"
# assert Qt6Recipe._version == "6.5.3"
assert Qt6Recipe._version == "6.10.2"
assert Qt6Recipe.depends == ['python3', 'hostqt6']
assert Qt6Recipe.python_depends == []
class Qt6RecipePinned(util.InheritedRecipeMixin, Qt6Recipe):
sha512sum = "0bdbe8b9a43390c98cf19e851ec5394bc78438d227cf9d0d7a3748aee9a32a7f14fc46f52d4fa283819f21413567080aee7225c566af5278557f5e1992674da3"
# sha512sum = "ca8ea3b81c121886636988275f7fa8ae6d19f7be02669e63ab19b4285b611057a41279db9532c25ae87baa3904b010e1db68b899cd0eda17a5a8d3d87098b4d5"
sha512sum = "bf1a1d42d57b4d2e77f7227f4cbe01e847fd65035461b89481063b32f25a57be6e5a07889acc4af65ca9ff9d27b7fe63bd2fe60b8aa7fa19d554394d799fbaa1"
recipe = Qt6RecipePinned()
@@ -1,13 +0,0 @@
from pythonforandroid.recipes.setuptools import SetuptoolsRecipe
assert SetuptoolsRecipe._version == "51.3.3"
assert SetuptoolsRecipe.depends == ['python3']
assert SetuptoolsRecipe.python_depends == []
class SetuptoolsRecipePinned(SetuptoolsRecipe):
sha512sum = "5a3572466a68c6f650111448ce3343f64c62044650bb8635edbff97e2bc7b216b8bbe3b4e3bccf34e6887f3bedc911b27ca5f9a515201cae49cf44fbacf03345"
recipe = SetuptoolsRecipePinned()
+9 -4
View File
@@ -1,13 +1,18 @@
from pythonforandroid.recipes.sip import SipRecipe
from pythonforandroid.util import HashPinnedDependency
assert SipRecipe._version == "6.7.9"
assert SipRecipe.depends == ["setuptools", "packaging", "tomli", "ply", "python3"], SipRecipe.depends
assert SipRecipe._version == "6.15.1"
assert SipRecipe.depends == ["python3"], SipRecipe.depends
assert SipRecipe.python_depends == []
class SipRecipePinned(SipRecipe):
sha512sum = "bb9d0d0d92002b6fd33f7e8ebe8cd62456dacc16b5734b73760b1ba14fb9b1f2b9b6640b40196c6cf5f345e1afde48bdef39675c4d3480041771325d4cf3c233"
sha512sum = "30a312419ba82c0221c0cf03c3fb3ad7d45bb8fe633d1d7477025a7986b0a7f7b7b781a8d9cd6bcdb78f3b872231fd1eed123a761b497861822f2e35093f574d"
hostpython_prerequisites = [
HashPinnedDependency(package="setuptools==80.9.0",
hashes=['sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922']),
]
recipe = SipRecipePinned()
Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 691 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 880 B

After

Width:  |  Height:  |  Size: 833 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 314 B

After

Width:  |  Height:  |  Size: 394 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 380 B

After

Width:  |  Height:  |  Size: 412 B

@@ -329,6 +329,7 @@ Pane {
}
}
}
property color navigationBarBackgroundColor: constants.highlightBackground
AddressDetails {
id: addressdetails
+4 -2
View File
@@ -107,9 +107,9 @@ Pane {
Layout.fillWidth: true
Layout.fillHeight: true
verticalPadding: 0
verticalPadding: bg.lineWidth
horizontalPadding: 0
background: PaneInsetBackground {}
background: PaneInsetBackground { id: bg; vertical: false }
ElListView {
id: listview
@@ -249,6 +249,7 @@ Pane {
ButtonContainer {
Layout.fillWidth: true
FlatButton {
Layout.fillWidth: true
Layout.preferredWidth: 1
@@ -275,6 +276,7 @@ Pane {
}
}
property color navigationBarBackgroundColor: constants.highlightBackground
Component {
id: sectionDelegate
@@ -37,6 +37,7 @@ ElDialog {
InfoTextArea {
Layout.fillWidth: true
Layout.margins: constants.paddingMedium
backgroundColor: constants.darkerDialogBackground
text: bip39RecoveryListModel.state == Bip39RecoveryListModel.Scanning
? qsTr('Scanning for accounts...')
@@ -65,7 +66,9 @@ ElDialog {
verticalPadding: 0
horizontalPadding: 0
background: PaneInsetBackground {}
background: PaneInsetBackground {
baseColor: constants.darkerDialogBackground
}
ColumnLayout {
spacing: 0
@@ -233,8 +233,8 @@ Pane {
}
}
}
property color navigationBarBackgroundColor: constants.highlightBackground
Component {
id: openChannelDialog
+9 -17
View File
@@ -145,14 +145,10 @@ Pane {
Layout.fillWidth: true
Layout.preferredHeight: 1
}
Pane {
background: Rectangle { color: Material.dialogColor }
padding: 0
FlatButton {
Layout.minimumWidth: implicitWidth
text: channeldetails.frozenForSending ? qsTr('Unfreeze') : qsTr('Freeze')
onClicked: channeldetails.freezeForSending()
}
Button {
Layout.minimumWidth: implicitWidth
text: channeldetails.frozenForSending ? qsTr('Unfreeze') : qsTr('Freeze')
onClicked: channeldetails.freezeForSending()
}
}
@@ -182,14 +178,10 @@ Pane {
Layout.fillWidth: true
Layout.preferredHeight: 1
}
Pane {
background: Rectangle { color: Material.dialogColor }
padding: 0
FlatButton {
Layout.minimumWidth: implicitWidth
text: channeldetails.frozenForReceiving ? qsTr('Unfreeze') : qsTr('Freeze')
onClicked: channeldetails.freezeForReceiving()
}
Button {
Layout.minimumWidth: implicitWidth
text: channeldetails.frozenForReceiving ? qsTr('Unfreeze') : qsTr('Freeze')
onClicked: channeldetails.freezeForReceiving()
}
}
@@ -466,8 +458,8 @@ Pane {
}
}
}
}
property color navigationBarBackgroundColor: constants.highlightBackground
ChannelDetails {
id: channeldetails
@@ -23,7 +23,7 @@ ElDialog {
property string channelBackup
function reset() {
function resetDialog() {
state = ''
errorText.text = ''
peerText.text = ''
@@ -81,7 +81,7 @@ ElDialog {
}
}
TextHighlightPane {
DialogHighlightPane {
Layout.alignment: Qt.AlignHCenter
Layout.preferredWidth: dialog.width * 3/4
Label {
@@ -100,6 +100,7 @@ ElDialog {
visible: false
iconStyle: InfoTextArea.IconStyle.Error
textFormat: TextEdit.PlainText
backgroundColor: constants.darkerDialogBackground
}
InfoTextArea {
@@ -108,6 +109,7 @@ ElDialog {
Layout.preferredWidth: dialog.width * 2/3
visible: false
textFormat: TextEdit.PlainText
backgroundColor: constants.darkerDialogBackground
}
}
+4 -6
View File
@@ -63,13 +63,10 @@ Pane {
Layout.fillWidth: true
Layout.fillHeight: true
Layout.topMargin: constants.paddingLarge
Layout.bottomMargin: constants.paddingLarge
Layout.leftMargin: constants.paddingMedium
Layout.rightMargin: constants.paddingMedium
verticalPadding: 0
verticalPadding: bg.lineWidth
horizontalPadding: 0
background: PaneInsetBackground {}
background: PaneInsetBackground { id: bg; vertical: false }
ColumnLayout {
spacing: 0
@@ -121,6 +118,7 @@ Pane {
ButtonContainer {
Layout.fillWidth: true
FlatButton {
Layout.fillWidth: true
Layout.preferredWidth: 1
@@ -157,8 +155,8 @@ Pane {
icon.source: '../../icons/lightning.png'
}
}
}
property color navigationBarBackgroundColor: constants.highlightBackground
Component {
id: openChannelDialog
@@ -70,7 +70,7 @@ ElDialog {
color: Material.accentColor
}
TextHighlightPane {
DialogHighlightPane {
Layout.columnSpan: 2
Layout.fillWidth: true
@@ -91,6 +91,7 @@ ElDialog {
Layout.fillWidth: true
Layout.bottomMargin: constants.paddingLarge
text: channeldetails.messageForceClose
backgroundColor: constants.darkerDialogBackground
}
Label {
@@ -140,6 +141,7 @@ ElDialog {
Layout.maximumWidth: parent.width
visible: !channeldetails.isClosing && errorText.text
iconStyle: InfoTextArea.IconStyle.Error
backgroundColor: constants.darkerDialogBackground
}
Label {
Layout.alignment: Qt.AlignHCenter
@@ -154,17 +156,21 @@ ElDialog {
}
}
FlatButton {
DialogButtonContainer {
Layout.columnSpan: 2
Layout.fillWidth: true
text: qsTr('Close channel')
icon.source: '../../icons/closebutton.png'
enabled: !channeldetails.isClosing
onClicked: {
if (closetypegroup.checkedButton.closetype == 'local_force') {
showBackupThenClose()
} else {
doCloseChannel()
FlatButton {
Layout.fillWidth: true
text: qsTr('Close channel')
icon.source: '../../icons/closebutton.png'
enabled: !channeldetails.isClosing
onClicked: {
if (closetypegroup.checkedButton.closetype == 'local_force') {
showBackupThenClose()
} else {
doCloseChannel()
}
}
}
}
+19 -12
View File
@@ -11,7 +11,7 @@ ElDialog {
id: dialog
required property QtObject finalizer
required property Amount satoshis
required property var satoshis // type: Amount
property string address
property string message
property bool showOptions: true
@@ -71,7 +71,7 @@ ElDialog {
color: Material.accentColor
}
TextHighlightPane {
DialogHighlightPane {
Layout.columnSpan: 2
Layout.fillWidth: true
GridLayout {
@@ -122,7 +122,7 @@ ElDialog {
color: Material.accentColor
}
TextHighlightPane {
DialogHighlightPane {
Layout.columnSpan: 2
Layout.fillWidth: true
height: feepicker.height
@@ -153,7 +153,7 @@ ElDialog {
visible: showOptions
}
TextHighlightPane {
DialogHighlightPane {
Layout.columnSpan: 2
Layout.fillWidth: true
visible: optionstoggle.visible && !optionstoggle.collapsed
@@ -214,6 +214,7 @@ ElDialog {
visible: finalizer.warning != ''
text: finalizer.warning
iconStyle: InfoTextArea.IconStyle.Warn
backgroundColor: constants.darkerDialogBackground
}
ToggleLabel {
@@ -234,6 +235,7 @@ ElDialog {
Layout.columnSpan: 2
Layout.fillWidth: true
visible: finalizer.valid
backgroundColor: constants.darkerDialogBackground
idx: index
model: modelData
@@ -258,6 +260,7 @@ ElDialog {
Layout.columnSpan: 2
Layout.fillWidth: true
visible: finalizer.valid
backgroundColor: constants.darkerDialogBackground
allowShare: false
allowClickAddress: false
@@ -270,15 +273,19 @@ ElDialog {
}
}
FlatButton {
id: sendButton
DialogButtonContainer {
Layout.fillWidth: true
text: (Daemon.currentWallet.isWatchOnly || !Daemon.currentWallet.canSignWithoutCosigner)
? qsTr('Finalize...')
: qsTr('Pay...')
icon.source: '../../icons/confirmed.png'
enabled: finalizer.valid
onClicked: doAccept()
FlatButton {
id: sendButton
Layout.fillWidth: true
text: (Daemon.currentWallet.isWatchOnly || !Daemon.currentWallet.canSignWithoutCosigner)
? qsTr('Finalize...')
: qsTr('Pay...')
icon.source: '../../icons/confirmed.png'
enabled: finalizer.valid
onClicked: doAccept()
}
}
}
+3 -1
View File
@@ -29,8 +29,10 @@ Item {
property color mutedForeground: 'gray' //Qt.lighter(Material.background, 2)
property color darkerBackground: Qt.darker(Material.background, 1.20)
property color lighterBackground: Qt.lighter(Material.background, 1.10)
property color darkerDialogBackground: Qt.darker(Material.dialogColor, 1.20)
property color highlightBackground: Qt.lighter(Material.background, 1.30)
property color dialogColor: Material.dialogColor
property color seedTextAreaBackground: Qt.darker(darkerDialogBackground, 1.20)
property color notificationBackground: Qt.lighter(Material.background, 1.5)
property color colorCredit: "#ff80ff80"
@@ -59,7 +59,7 @@ ElDialog {
color: Material.accentColor
}
TextHighlightPane {
DialogHighlightPane {
Layout.columnSpan: 2
Layout.fillWidth: true
height: feepicker_childinfo.height
@@ -82,7 +82,7 @@ ElDialog {
color: Material.accentColor
}
TextHighlightPane {
DialogHighlightPane {
Layout.columnSpan: 2
Layout.fillWidth: true
@@ -159,6 +159,7 @@ ElDialog {
visible: cpfpfeebumper.warning != ''
text: cpfpfeebumper.warning
iconStyle: InfoTextArea.IconStyle.Warn
backgroundColor: constants.darkerDialogBackground
}
ToggleLabel {
@@ -213,13 +214,16 @@ ElDialog {
}
}
FlatButton {
id: sendButton
DialogButtonContainer {
Layout.fillWidth: true
text: qsTr('Ok')
icon.source: '../../icons/confirmed.png'
enabled: cpfpfeebumper.valid
onClicked: doAccept()
FlatButton {
id: sendButton
Layout.fillWidth: true
text: qsTr('Ok')
icon.source: '../../icons/confirmed.png'
enabled: cpfpfeebumper.valid
onClicked: doAccept()
}
}
}
}
@@ -39,7 +39,7 @@ ElDialog {
width: parent.width
spacing: constants.paddingMedium
TextHighlightPane {
DialogHighlightPane {
Layout.fillWidth: true
Layout.leftMargin: constants.paddingMedium
Layout.rightMargin: constants.paddingMedium
@@ -61,6 +61,7 @@ ElDialog {
Layout.margins: constants.paddingLarge
visible: dialog.text_help
text: dialog.text_help
backgroundColor: constants.darkerDialogBackground
}
InfoTextArea {
@@ -72,11 +73,12 @@ ElDialog {
visible: dialog.text_warn
text: dialog.text_warn
iconStyle: InfoTextArea.IconStyle.Warn
backgroundColor: constants.darkerDialogBackground
}
}
}
ButtonContainer {
DialogButtonContainer {
id: buttons
Layout.fillWidth: true
@@ -42,7 +42,7 @@ ElDialog {
width: parent.width
spacing: constants.paddingMedium
TextHighlightPane {
DialogHighlightPane {
Layout.alignment: Qt.AlignHCenter
Layout.fillWidth: true
Layout.leftMargin: constants.paddingMedium
@@ -60,7 +60,7 @@ ElDialog {
Layout.bottomMargin: constants.paddingMedium
}
TextHighlightPane {
DialogHighlightPane {
Layout.fillWidth: true
visible: dialog.text
@@ -84,11 +84,12 @@ ElDialog {
visible: dialog.text_help
text: dialog.text_help
Layout.fillWidth: true
backgroundColor: constants.darkerDialogBackground
}
}
}
ButtonContainer {
DialogButtonContainer {
Layout.fillWidth: true
FlatButton {
+2 -2
View File
@@ -14,8 +14,8 @@ Pane {
padding: 0
clip: true
background: Rectangle {
color: constants.darkerBackground
background: PaneInsetBackground {
vertical: false
}
ElListView {
@@ -84,7 +84,6 @@ ElDialog {
icon.source: '../../icons/qrcode.png'
icon.height: constants.iconSizeMedium
icon.width: constants.iconSizeMedium
scale: 1.2
onClicked: {
var dialog = app.scanDialog.createObject(app, {
hint: Daemon.currentWallet.isWatchOnly
@@ -1,98 +0,0 @@
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls
import org.electrum 1.0
import "controls"
ElDialog {
id: root
property bool valid: false
width: parent.width
height: parent.height
padding: 0
title: qsTr('Import channel backup')
iconSource: Qt.resolvedUrl('../../icons/file.png')
function verifyChannelBackup(text) {
return valid = Daemon.currentWallet.isValidChannelBackup(text)
}
onAccepted: {
Daemon.currentWallet.importChannelBackup(channelbackup_ta.text)
}
ColumnLayout {
anchors.fill: parent
spacing: 0
RowLayout {
Layout.fillWidth: true
Layout.leftMargin: constants.paddingLarge
TextArea {
id: channelbackup_ta
Layout.fillWidth: true
Layout.minimumHeight: 80
font.family: FixedFont
focus: true
wrapMode: TextEdit.WrapAnywhere
onTextChanged: verifyChannelBackup(text)
}
ColumnLayout {
ToolButton {
icon.source: '../../icons/paste.png'
icon.height: constants.iconSizeMedium
icon.width: constants.iconSizeMedium
onClicked: {
channelbackup_ta.text = AppController.clipboardToText()
}
}
ToolButton {
icon.source: '../../icons/qrcode.png'
icon.height: constants.iconSizeMedium
icon.width: constants.iconSizeMedium
scale: 1.2
onClicked: {
var dialog = app.scanDialog.createObject(app, {
hint: qsTr('Scan a channel backup')
})
dialog.onFoundText.connect(function(data) {
channelbackup_ta.text = data
dialog.close()
})
dialog.open()
}
}
}
}
TextArea {
id: validationtext
visible: text
Layout.fillWidth: true
Layout.leftMargin: constants.paddingLarge
readOnly: true
wrapMode: TextInput.WordWrap
background: Rectangle {
color: 'transparent'
}
}
Item { Layout.preferredWidth: 1; Layout.fillHeight: true }
FlatButton {
Layout.fillWidth: true
enabled: valid
text: qsTr('Import')
onClicked: doAccept()
}
}
}
+13 -10
View File
@@ -10,7 +10,7 @@ import "controls"
ElDialog {
id: dialog
property Invoice invoice
property var invoice // type Invoice
property bool payImmediately: false
property string broadcastTxid
@@ -24,7 +24,7 @@ ElDialog {
property bool _canMax: invoice.invoiceType == Invoice.OnchainInvoice
property Amount _invoice_amount: invoice.amount
property var _invoice_amount: invoice.amount // type: Amount
ColumnLayout {
anchors.fill: parent
@@ -67,6 +67,7 @@ ElDialog {
? InfoTextArea.IconStyle.Pending
: InfoTextArea.IconStyle.Error
: InfoTextArea.IconStyle.Info
backgroundColor: constants.darkerDialogBackground
}
Label {
@@ -77,7 +78,7 @@ ElDialog {
color: Material.accentColor
}
TextHighlightPane {
DialogHighlightPane {
Layout.columnSpan: 2
Layout.fillWidth: true
visible: invoice.invoiceType == Invoice.OnchainInvoice
@@ -114,7 +115,7 @@ ElDialog {
color: Material.accentColor
}
TextHighlightPane {
DialogHighlightPane {
Layout.columnSpan: 2
Layout.fillWidth: true
@@ -137,7 +138,7 @@ ElDialog {
color: Material.accentColor
}
TextHighlightPane {
DialogHighlightPane {
id: amountContainer
Layout.columnSpan: 2
@@ -294,6 +295,8 @@ ElDialog {
id: maxAmountMessage
visible: amountMax.checked && text
compact: true
backgroundColor: constants.darkerDialogBackground
Connections {
target: invoice
function onMaxAmountMessage(message) {
@@ -320,7 +323,7 @@ ElDialog {
color: Material.accentColor
}
TextHighlightPane {
DialogHighlightPane {
Layout.columnSpan: 2
Layout.fillWidth: true
@@ -358,7 +361,7 @@ ElDialog {
color: Material.accentColor
}
TextHighlightPane {
DialogHighlightPane {
Layout.columnSpan: 2
Layout.fillWidth: true
@@ -401,7 +404,7 @@ ElDialog {
visible: 'r' in invoice.lnprops && invoice.lnprops.r.length
model: invoice.lnprops.r
TextHighlightPane {
DialogHighlightPane {
Layout.columnSpan: 2
Layout.fillWidth: true
@@ -428,7 +431,7 @@ ElDialog {
color: Material.accentColor
}
TextHighlightPane {
DialogHighlightPane {
Layout.columnSpan: 2
Layout.fillWidth: true
visible: invoice.invoiceType == Invoice.LightningInvoice && invoice.address
@@ -458,7 +461,7 @@ ElDialog {
}
}
ButtonContainer {
DialogButtonContainer {
Layout.fillWidth: true
FlatButton {
+5 -3
View File
@@ -18,7 +18,6 @@ Pane {
ColumnLayout {
Layout.fillWidth: true
Layout.margins: constants.paddingLarge
InfoTextArea {
Layout.fillWidth: true
@@ -32,9 +31,9 @@ Pane {
}
Frame {
background: PaneInsetBackground {}
background: PaneInsetBackground {id: bg; vertical: false}
verticalPadding: 0
verticalPadding: bg.lineWidth
horizontalPadding: 0
Layout.fillHeight: true
Layout.fillWidth: true
@@ -87,6 +86,7 @@ Pane {
ButtonContainer {
Layout.fillWidth: true
FlatButton {
Layout.fillWidth: true
Layout.preferredWidth: 1
@@ -112,4 +112,6 @@ Pane {
}
}
}
property color navigationBarBackgroundColor: constants.highlightBackground
}
@@ -13,7 +13,7 @@ ElDialog {
title: qsTr('LNURL Payment request')
iconSource: '../../../icons/link.png'
property InvoiceParser invoiceParser
property var invoiceParser // type: InvoiceParser
padding: 0
needsSystemBarPadding: false
@@ -43,6 +43,7 @@ ElDialog {
compact: true
visible: invoiceParser.lnurlData['min_sendable_sat'] != invoiceParser.lnurlData['max_sendable_sat']
text: qsTr('Amount must be between %1 and %2 %3').arg(Config.formatSats(invoiceParser.lnurlData['min_sendable_sat'])).arg(Config.formatSats(invoiceParser.lnurlData['max_sendable_sat'])).arg(Config.baseUnit)
backgroundColor: constants.darkerDialogBackground
}
Label {
@@ -129,15 +130,18 @@ ElDialog {
}
}
FlatButton {
DialogButtonContainer {
Layout.topMargin: constants.paddingLarge
Layout.fillWidth: true
text: qsTr('Pay...')
icon.source: '../../icons/confirmed.png'
enabled: valid
onClicked: {
invoiceParser.lnurlGetInvoice(comment.text)
dialog.close()
FlatButton {
Layout.fillWidth: true
text: qsTr('Pay...')
icon.source: '../../icons/confirmed.png'
enabled: valid
onClicked: {
invoiceParser.lnurlGetInvoice(comment.text)
dialog.close()
}
}
}
}
@@ -13,8 +13,8 @@ ElDialog {
title: qsTr('LNURL Withdraw request')
iconSource: '../../../icons/link.png'
property Wallet wallet: Daemon.currentWallet
property RequestDetails requestDetails
property var wallet: Daemon.currentWallet // type: Wallet
property var requestDetails // type: RequestDetails
padding: 0
needsSystemBarPadding: false
@@ -50,6 +50,7 @@ ElDialog {
ColumnLayout {
width: parent.width
spacing: 0
GridLayout {
id: rootLayout
@@ -75,6 +76,7 @@ ElDialog {
+ '\n\n'
+ qsTr('Do a submarine swap in the \'Channels\' tab to get more incoming liquidity.')
iconStyle: InfoTextArea.IconStyle.Error
backgroundColor: constants.darkerDialogBackground
}
InfoTextArea {
@@ -83,9 +85,10 @@ ElDialog {
compact: true
visible: !dialog.insufficientLiquidity && dialog.providerMinWithdrawable != dialog.providerMaxWithdrawable
text: qsTr('Amount must be between %1 and %2 %3')
.arg(Config.formatSats(dialog.effectiveMinWithdrawable))
.arg(Config.formatSats(dialog.effectiveMaxWithdrawable))
.arg(Config.baseUnit)
.arg(Config.formatSats(dialog.effectiveMinWithdrawable))
.arg(Config.formatSats(dialog.effectiveMaxWithdrawable))
.arg(Config.baseUnit)
backgroundColor: constants.darkerDialogBackground
}
InfoTextArea {
@@ -99,6 +102,7 @@ ElDialog {
+ ' '
+ qsTr('You may need to do a submarine swap to increase your incoming liquidity.')
iconStyle: InfoTextArea.IconStyle.Warn
backgroundColor: constants.darkerDialogBackground
}
Label {
@@ -160,16 +164,19 @@ ElDialog {
}
}
FlatButton {
DialogButtonContainer {
Layout.topMargin: constants.paddingLarge
Layout.fillWidth: true
text: qsTr('Withdraw...')
icon.source: '../../icons/confirmed.png'
enabled: valid && !requestDetails.busy
onClicked: {
var satsAmount = amountBtc.textAsSats.satsInt;
requestDetails.lnurlRequestWithdrawal(satsAmount);
dialog.close();
FlatButton {
Layout.fillWidth: true
text: qsTr('Withdraw...')
icon.source: '../../icons/confirmed.png'
enabled: valid && !requestDetails.busy
onClicked: {
var satsAmount = amountBtc.textAsSats.satsInt;
requestDetails.lnurlRequestWithdrawal(satsAmount);
dialog.close();
}
}
}
}
@@ -46,8 +46,13 @@ ElDialog {
}
}
ButtonContainer {
DialogButtonContainer {
Layout.fillWidth: true
function beforeLayout() {
if (!dialog.text) {
headerComponent = null
}
}
FlatButton {
Layout.fillWidth: true
@@ -314,6 +314,7 @@ Pane {
}
}
}
property color navigationBarBackgroundColor: constants.highlightBackground
Component {
id: serverConfig
@@ -50,21 +50,25 @@ ElDialog {
Layout.fillHeight: true
Layout.leftMargin: constants.paddingLarge
Layout.rightMargin: constants.paddingLarge
Layout.bottomMargin: constants.paddingLarge
TextHighlightPane {
InfoTextArea {
Layout.fillWidth: true
Label {
text: qsTr('Enter the list of Nostr relays') + '<br/><br/>' +
qsTr('Nostr relays are used to send and receive submarine swap offers.') +
' ' + qsTr('For multisig wallets, nostr is also used to relay transactions to your co-signers.') +
' ' + qsTr('Connections to nostr are only made when required, and ephemerally.')
width: parent.width
wrapMode: Text.Wrap
}
Layout.bottomMargin: constants.paddingLarge
compact: true
text: qsTr('Nostr relays are used to send and receive submarine swap offers.') +
' ' + qsTr('For multisig wallets, nostr is also used to relay transactions to your co-signers.') +
' ' + qsTr('Connections to nostr are only made when required, and ephemerally.')
backgroundColor: constants.darkerDialogBackground
}
Label {
text: qsTr('Enter the list of Nostr relays')
}
RowLayout {
Layout.fillWidth: true
Layout.topMargin: constants.paddingLarge
ElTextArea {
id: relays_ta
Layout.fillWidth: true
@@ -96,14 +100,18 @@ ElDialog {
}
}
FlatButton {
DialogButtonContainer {
Layout.fillWidth: true
text: qsTr('Ok')
enabled: valid
icon.source: '../../icons/confirmed.png'
onClicked: {
Config.nostrRelays = clean_array(relays_ta.text).join(",")
rootItem.close()
FlatButton {
Layout.fillWidth: true
text: qsTr('Ok')
enabled: valid
icon.source: '../../icons/confirmed.png'
onClicked: {
Config.nostrRelays = clean_array(relays_ta.text).join(",")
rootItem.close()
}
}
}
}
@@ -55,6 +55,7 @@ ElDialog {
'\n\n',
qsTr('If you want to have recoverable channels, you must create a new wallet with an Electrum seed')
].join('')
backgroundColor: constants.darkerDialogBackground
}
InfoTextArea {
@@ -65,80 +66,79 @@ ElDialog {
text: [ qsTr('You currently have recoverable channels setting disabled.'),
qsTr('This means your channels cannot be recovered from seed.')
].join(' ')
}
Label {
text: qsTr('Node')
Layout.columnSpan: 3
color: Material.accentColor
backgroundColor: constants.darkerDialogBackground
}
// gossip
TextArea {
id: node
visible: Config.useGossip
Layout.columnSpan: 2
Layout.fillWidth: true
font.family: FixedFont
wrapMode: Text.Wrap
placeholderText: qsTr('Paste or scan node uri/pubkey')
inputMethodHints: Qt.ImhSensitiveData | Qt.ImhNoPredictiveText | Qt.ImhNoAutoUppercase
onTextChanged: {
if (activeFocus)
channelopener.connectStr = text
}
onActiveFocusChanged: {
if (!activeFocus)
channelopener.connectStr = text
}
}
RowLayout {
Layout.columnSpan: 3
visible: Config.useGossip
spacing: 0
ToolButton {
icon.source: '../../icons/paste.png'
icon.height: constants.iconSizeMedium
icon.width: constants.iconSizeMedium
onClicked: {
var cliptext = AppController.clipboardToText()
if (!cliptext)
return
if (channelopener.validateConnectString(cliptext)) {
channelopener.connectStr = cliptext
node.text = channelopener.connectStr
} else {
var dialog = app.messageDialog.createObject(app, {
text: qsTr('Invalid node-id or connect string')
TextArea {
id: nodeUri
visible: Config.useGossip
Layout.fillWidth: true
Layout.minimumHeight: nodeUriFontMetrics.lineSpacing * 4 + topPadding + bottomPadding
Layout.topMargin: constants.paddingSmall
font.family: FixedFont
wrapMode: Text.Wrap
placeholderText: qsTr('Paste or scan node uri/pubkey')
inputMethodHints: Qt.ImhSensitiveData | Qt.ImhNoPredictiveText | Qt.ImhNoAutoUppercase
onTextChanged: {
if (activeFocus)
channelopener.connectStr = text
}
onActiveFocusChanged: {
if (!activeFocus)
channelopener.connectStr = text
}
}
ColumnLayout {
spacing: 0
ToolButton {
icon.source: '../../icons/paste.png'
icon.height: constants.iconSizeMedium
icon.width: constants.iconSizeMedium
onClicked: {
var cliptext = AppController.clipboardToText()
if (!cliptext)
return
if (channelopener.validateConnectString(cliptext)) {
channelopener.connectStr = cliptext
nodeUri.text = channelopener.connectStr
} else {
var dialog = app.messageDialog.createObject(app, {
text: qsTr('Invalid node-id or connect string')
})
dialog.open()
}
}
}
ToolButton {
icon.source: '../../icons/qrcode.png'
icon.height: constants.iconSizeMedium
icon.width: constants.iconSizeMedium
onClicked: {
var dialog = app.scanDialog.createObject(app, {
hint: qsTr('Scan a node-id or a connect string')
})
dialog.onFoundText.connect(function(data) {
if (channelopener.validateConnectString(data)) {
channelopener.connectStr = data
nodeUri.text = channelopener.connectStr
} else {
var errdialog = app.messageDialog.createObject(app, {
text: qsTr('Invalid node-id or connect string')
})
errdialog.open()
}
dialog.close()
})
dialog.open()
}
}
}
ToolButton {
icon.source: '../../icons/qrcode.png'
icon.height: constants.iconSizeMedium
icon.width: constants.iconSizeMedium
scale: 1.2
onClicked: {
var dialog = app.scanDialog.createObject(app, {
hint: qsTr('Scan a node-id or a connect string')
})
dialog.onFoundText.connect(function(data) {
if (channelopener.validateConnectString(data)) {
channelopener.connectStr = data
node.text = channelopener.connectStr
} else {
var errdialog = app.messageDialog.createObject(app, {
text: qsTr('Invalid node-id or connect string')
})
errdialog.open()
}
dialog.close()
})
dialog.open()
}
}
}
// trampoline
@@ -160,11 +160,7 @@ ElDialog {
}
}
Label {
text: qsTr('Amount')
Layout.columnSpan: 3
color: Material.accentColor
}
Item { Layout.columnSpan: 3; width: 1; height: constants.paddingLarge }
BtcField {
id: amountBtc
@@ -238,17 +234,21 @@ ElDialog {
text: channelopener.warning
visible: text
compact: true
backgroundColor: constants.darkerDialogBackground
}
}
}
FlatButton {
DialogButtonContainer {
Layout.fillWidth: true
text: qsTr('Open Channel...')
icon.source: '../../icons/confirmed.png'
enabled: channelopener.valid
onClicked: channelopener.openChannel()
FlatButton {
Layout.fillWidth: true
text: qsTr('Open Channel...')
icon.source: '../../icons/confirmed.png'
enabled: channelopener.valid
onClicked: channelopener.openChannel()
}
}
}
@@ -298,7 +298,7 @@ ElDialog {
}
onChannelOpening: (peer) => {
console.log('Channel is opening')
app.channelOpenProgressDialog.reset()
app.channelOpenProgressDialog.resetDialog()
app.channelOpenProgressDialog.peer = peer
app.channelOpenProgressDialog.open()
}
@@ -327,4 +327,8 @@ ElDialog {
id: amountFontMetrics
font: amountBtc.font
}
FontMetrics {
id: nodeUriFontMetrics
font: nodeUri.font
}
}
@@ -41,23 +41,20 @@ ElDialog {
InfoTextArea {
id: notice
Layout.fillWidth: true
Layout.bottomMargin: constants.paddingSmall
text: Daemon.singlePasswordEnabled || isStartup
? qsTr('Please enter password')
: qsTr('Wallet <b>%1</b> requires password to unlock').arg(name)
iconStyle: InfoTextArea.IconStyle.Warn
Layout.fillWidth: true
}
Label {
text: qsTr('Password')
Layout.fillWidth: true
color: Material.accentColor
compact: true
iconStyle: InfoTextArea.IconStyle.Info
backgroundColor: constants.darkerDialogBackground
}
PasswordField {
id: password
Layout.fillWidth: true
Layout.leftMargin: constants.paddingXLarge
placeholderText: qsTr('Password')
onTextChanged: {
unlockButton.enabled = true
@@ -77,16 +74,19 @@ ElDialog {
}
}
FlatButton {
id: unlockButton
DialogButtonContainer {
Layout.fillWidth: true
icon.source: '../../icons/unlock.png'
text: qsTr("Unlock")
onClicked: {
unlock()
FlatButton {
id: unlockButton
Layout.fillWidth: true
icon.source: '../../icons/unlock.png'
text: qsTr("Unlock")
onClicked: {
unlock()
}
}
}
}
function unlock() {
+17 -22
View File
@@ -39,32 +39,23 @@ ElDialog {
text: infotext
Layout.bottomMargin: constants.paddingMedium
Layout.fillWidth: true
}
Label {
Layout.fillWidth: true
text: qsTr('Password')
color: Material.accentColor
backgroundColor: constants.darkerDialogBackground
compact: true
}
PasswordField {
id: pw_1
Layout.leftMargin: constants.paddingXLarge
}
Label {
Layout.fillWidth: true
text: qsTr('Password (again)')
visible: confirmPassword
color: Material.accentColor
Layout.bottomMargin: constants.paddingSmall
placeholderText: qsTr('Password')
}
PasswordField {
id: pw_2
Layout.leftMargin: constants.paddingXLarge
Layout.bottomMargin: constants.paddingSmall
visible: confirmPassword
showReveal: false
echoMode: pw_1.echoMode
placeholderText: qsTr('Password (again)')
}
RowLayout {
@@ -82,7 +73,7 @@ ElDialog {
}
PasswordStrengthIndicator {
Layout.fillWidth: true
Layout.preferredWidth: passworddialog.width / 2
password: pw_1.text
}
}
@@ -98,13 +89,17 @@ ElDialog {
}
}
FlatButton {
DialogButtonContainer {
Layout.fillWidth: true
text: qsTr("Ok")
icon.source: '../../icons/confirmed.png'
enabled: confirmPassword ? pw_1.text.length >= 6 && pw_1.text == pw_2.text : true
onClicked: {
passwordEntered(pw_1.text)
FlatButton {
Layout.fillWidth: true
text: qsTr("Ok")
icon.source: '../../icons/confirmed.png'
enabled: confirmPassword ? pw_1.text.length >= 6 && pw_1.text == pw_2.text : true
onClicked: {
passwordEntered(pw_1.text)
}
}
}
}
@@ -32,13 +32,17 @@ ElDialog {
Item { Layout.fillHeight: true; Layout.preferredWidth: 1 }
FlatButton {
DialogButtonContainer {
Layout.fillWidth: true
text: qsTr('Ok')
icon.source: '../../icons/confirmed.png'
onClicked: {
Network.proxy = proxyconfig.toProxyDict()
rootItem.close()
FlatButton {
Layout.fillWidth: true
text: qsTr('Ok')
icon.source: '../../icons/confirmed.png'
onClicked: {
Network.proxy = proxyconfig.toProxyDict()
rootItem.close()
}
}
}
}
@@ -46,6 +46,7 @@ ElDialog {
Layout.fillWidth: true
Layout.bottomMargin: constants.paddingLarge
text: qsTr('Move the slider to increase your transaction\'s fee. This will improve its position in the mempool')
backgroundColor: constants.darkerDialogBackground
}
Label {
@@ -107,7 +108,7 @@ ElDialog {
color: Material.accentColor
}
TextHighlightPane {
DialogHighlightPane {
Layout.columnSpan: 2
Layout.fillWidth: true
height: feepicker.height
@@ -127,7 +128,7 @@ ElDialog {
color: Material.accentColor
}
TextHighlightPane {
DialogHighlightPane {
Layout.columnSpan: 2
Layout.fillWidth: true
visible: !optionstoggle.collapsed
@@ -167,6 +168,7 @@ ElDialog {
iconStyle: InfoTextArea.IconStyle.Warn
visible: rbffeebumper.warning != ''
text: rbffeebumper.warning
backgroundColor: constants.darkerDialogBackground
}
ToggleLabel {
@@ -221,13 +223,17 @@ ElDialog {
}
}
FlatButton {
id: sendButton
DialogButtonContainer {
Layout.fillWidth: true
text: qsTr('Ok')
icon.source: '../../icons/confirmed.png'
enabled: rbffeebumper.valid
onClicked: doAccept()
FlatButton {
id: sendButton
Layout.fillWidth: true
text: qsTr('Ok')
icon.source: '../../icons/confirmed.png'
enabled: rbffeebumper.valid
onClicked: doAccept()
}
}
}
}
@@ -43,6 +43,7 @@ ElDialog {
Layout.fillWidth: true
Layout.bottomMargin: constants.paddingLarge
text: qsTr('Cancel an unconfirmed transaction by double-spending its inputs back to your wallet with a higher fee.')
backgroundColor: constants.darkerDialogBackground
}
Label {
@@ -79,7 +80,7 @@ ElDialog {
color: Material.accentColor
}
TextHighlightPane {
DialogHighlightPane {
Layout.columnSpan: 2
Layout.fillWidth: true
height: feepicker.height
@@ -99,6 +100,7 @@ ElDialog {
iconStyle: InfoTextArea.IconStyle.Warn
visible: txcanceller.warning != ''
text: txcanceller.warning
backgroundColor: constants.darkerDialogBackground
}
ToggleLabel {
@@ -153,13 +155,17 @@ ElDialog {
}
}
FlatButton {
id: confirmButton
DialogButtonContainer {
Layout.fillWidth: true
text: qsTr('Ok')
icon.source: '../../icons/confirmed.png'
enabled: txcanceller.valid
onClicked: doAccept()
FlatButton {
id: confirmButton
Layout.fillWidth: true
text: qsTr('Ok')
icon.source: '../../icons/confirmed.png'
enabled: txcanceller.valid
onClicked: doAccept()
}
}
}
}
@@ -95,7 +95,7 @@ ElDialog {
}
}
ButtonContainer {
DialogButtonContainer {
Layout.fillWidth: true
FlatButton {
@@ -50,7 +50,7 @@ ElDialog {
width: parent.width
spacing: constants.paddingMedium
TextHighlightPane {
DialogHighlightPane {
Layout.alignment: Qt.AlignHCenter
Layout.fillWidth: true
@@ -143,7 +143,7 @@ ElDialog {
}
ButtonContainer {
DialogButtonContainer {
id: buttons
Layout.fillWidth: true
@@ -21,7 +21,6 @@ Pane {
ColumnLayout {
Layout.fillWidth: true
Layout.margins: constants.paddingLarge
InfoTextArea {
Layout.fillWidth: true
@@ -31,13 +30,13 @@ Pane {
}
Heading {
text: qsTr('Pending requests')
text: qsTr('Pending payment requests')
}
Frame {
background: PaneInsetBackground {}
background: PaneInsetBackground {id: bg; vertical: false}
verticalPadding: 0
verticalPadding: bg.lineWidth
horizontalPadding: 0
Layout.fillHeight: true
Layout.fillWidth: true
@@ -108,4 +107,5 @@ Pane {
}
}
}
property color navigationBarBackgroundColor: constants.highlightBackground
}
+4 -1
View File
@@ -6,7 +6,8 @@ import org.electrum
import "controls"
// currently not used on android, kept for future use when qt6 camera stops crashing
// currently not used on android, kept for testing on desktop, and future use
// on android when qt6 camera support becomes usable (i.e. stops crashing)
ElDialog {
id: scanDialog
@@ -50,4 +51,6 @@ ElDialog {
onClicked: doReject()
}
}
onClosed: destroy()
}
+3 -3
View File
@@ -11,8 +11,8 @@ import "controls"
ElDialog {
id: dialog
property InvoiceParser invoiceParser
property PIResolver piResolver
property var invoiceParser // type: InvoiceParser
property var piResolver // type: PIResolver
signal txFound(data: string)
signal channelBackupFound(data: string)
@@ -66,7 +66,7 @@ ElDialog {
}
}
ButtonContainer {
DialogButtonContainer {
Layout.fillWidth: true
FlatButton {
@@ -26,27 +26,31 @@ ElDialog {
ColumnLayout {
Layout.fillWidth: true
Layout.fillHeight: true
Layout.leftMargin: constants.paddingLarge
Layout.rightMargin: constants.paddingLarge
ServerConfig {
id: serverconfig
Layout.fillWidth: true
Layout.fillHeight: true
Layout.leftMargin: constants.paddingLarge
Layout.rightMargin: constants.paddingLarge
}
}
FlatButton {
DialogButtonContainer {
Layout.fillWidth: true
text: qsTr('Ok')
enabled: serverconfig.addressValid
icon.source: '../../icons/confirmed.png'
onClicked: {
let auto_connect = serverconfig.serverConnectMode == ServerConnectModeComboBox.Mode.Autoconnect
let server = serverconfig.address
let one_server = serverconfig.serverConnectMode == ServerConnectModeComboBox.Mode.Single
Network.setServerParameters(server, auto_connect, one_server)
rootItem.close()
FlatButton {
Layout.fillWidth: true
text: qsTr('Ok')
enabled: serverconfig.addressValid
icon.source: '../../icons/confirmed.png'
onClicked: {
let auto_connect = serverconfig.serverConnectMode == ServerConnectModeComboBox.Mode.Autoconnect
let server = serverconfig.address
let one_server = serverconfig.serverConnectMode == ServerConnectModeComboBox.Mode.Single
Network.setServerParameters(server, auto_connect, one_server)
rootItem.close()
}
}
}
}
@@ -179,8 +179,9 @@ ElDialog {
}
}
ButtonContainer {
DialogButtonContainer {
Layout.fillWidth: true
FlatButton {
Layout.fillWidth: true
Layout.preferredWidth: 1
+20 -24
View File
@@ -42,6 +42,7 @@ ElDialog {
: swaphelper.state == SwapHelper.NoService
? InfoTextArea.IconStyle.Warn
: InfoTextArea.IconStyle.Info
backgroundColor: constants.darkerDialogBackground
}
GridLayout {
@@ -252,37 +253,32 @@ ElDialog {
}
Pane {
Button {
Layout.alignment: Qt.AlignHCenter
visible: _swaphelper.isNostr()
background: Rectangle { color: constants.darkerDialogBackground }
padding: 0
FlatButton {
text: qsTr('Choose swap provider')
enabled: _swaphelper.state != SwapHelper.Initializing
&& _swaphelper.state != SwapHelper.Started
&& _swaphelper.state != SwapHelper.Success
&& _swaphelper.availableSwapServers.count
onClicked: {
var dialog = app.nostrSwapServersDialog.createObject(app, {
swaphelper: _swaphelper,
selectedPubkey: Config.swapServerNPub
})
dialog.accepted.connect(function() {
if (Config.swapServerNPub != dialog.selectedPubkey) {
Config.swapServerNPub = dialog.selectedPubkey
_swaphelper.setReadyState()
}
})
dialog.open()
}
text: qsTr('Choose swap provider')
enabled: _swaphelper.state != SwapHelper.Initializing
&& _swaphelper.state != SwapHelper.Started
&& _swaphelper.state != SwapHelper.Success
&& _swaphelper.availableSwapServers.count
onClicked: {
var dialog = app.nostrSwapServersDialog.createObject(app, {
swaphelper: _swaphelper,
selectedPubkey: Config.swapServerNPub
})
dialog.accepted.connect(function() {
if (Config.swapServerNPub != dialog.selectedPubkey) {
Config.swapServerNPub = dialog.selectedPubkey
_swaphelper.setReadyState()
}
})
dialog.open()
}
}
Item { Layout.fillHeight: true; Layout.preferredWidth: 1 }
ButtonContainer {
DialogButtonContainer {
Layout.columnSpan: 2
Layout.fillWidth: true
FlatButton {
+18 -12
View File
@@ -58,8 +58,10 @@ ElDialog {
RowLayout {
Layout.fillWidth: true
TextHighlightPane {
DialogHighlightPane {
Layout.fillWidth: true
Label {
text: qsTr('Enter the list of private keys to sweep into this wallet')
width: parent.width
@@ -112,7 +114,6 @@ ElDialog {
icon.source: '../../icons/qrcode.png'
icon.height: constants.iconSizeMedium
icon.width: constants.iconSizeMedium
scale: 1.2
onClicked: {
var dialog = app.scanDialog.createObject(app, {
hint: qsTr('Scan a private key')
@@ -133,24 +134,29 @@ ElDialog {
iconStyle: InfoTextArea.IconStyle.Warn
Layout.fillWidth: true
Layout.margins: constants.paddingMedium
backgroundColor: constants.darkerDialogBackground
visible: text
}
}
}
FlatButton {
DialogButtonContainer {
Layout.fillWidth: true
Layout.preferredWidth: 1
enabled: valid
icon.source: '../../icons/tab_send.png'
text: qsTr('Sweep...')
onClicked: {
console.log('sweeping')
root.privateKeys = sweepkeys.text
root.accept()
headerComponent: null
FlatButton {
Layout.fillWidth: true
Layout.preferredWidth: 1
enabled: valid
icon.source: '../../icons/tab_send.png'
text: qsTr('Sweep...')
onClicked: {
console.log('sweeping')
root.privateKeys = sweepkeys.text
root.accept()
}
}
}
}
Bitcoin {
@@ -480,6 +480,7 @@ Pane {
}
}
property color navigationBarBackgroundColor: constants.highlightBackground
TxDetails {
id: txdetails
@@ -517,6 +517,7 @@ Pane {
}
}
}
property color navigationBarBackgroundColor: constants.highlightBackground
Connections {
target: Daemon
@@ -2,6 +2,7 @@ import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import QtQuick.Controls.Material
import QtQuick.Controls.Material.impl
import QtQml
import org.electrum 1.0
@@ -302,6 +303,7 @@ Item {
var dialog = receiveDetailsDialog.createObject(mainView)
dialog.open()
}
pressAndHoldIndicator: true
onPressAndHold: {
Config.userKnowsPressAndHold = true
Daemon.currentWallet.deleteExpiredRequests()
@@ -316,6 +318,7 @@ Item {
text: qsTr('Send')
enabled: !invoiceParser.busy && !piResolver.busy && !requestDetails.busy
onClicked: openSendDialog()
pressAndHoldIndicator: true
onPressAndHold: {
Config.userKnowsPressAndHold = true
app.stack.push(Qt.resolvedUrl('Invoices.qml'))
@@ -324,6 +327,7 @@ Item {
}
}
}
property color navigationBarBackgroundColor: constants.highlightBackground
PIResolver {
id: piResolver
@@ -1,128 +0,0 @@
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls
import QtQuick.Controls.Material
import org.electrum 1.0
import "controls"
Item {
id: root
clip: true
implicitHeight: 0
function open() {
state = 'opened'
}
function close() {
state = ''
}
function toggle() {
if (state == 'opened')
state = ''
else
state = 'opened'
}
states: [
State {
name: 'opened'
PropertyChanges { target: root; implicitHeight: detailsPane.height }
}
]
transitions: [
Transition {
from: ''
to: 'opened'
NumberAnimation { target: root; properties: 'implicitHeight'; duration: 200 }
},
Transition {
from: 'opened'
to: ''
NumberAnimation { target: root; properties: 'implicitHeight'; duration: 100 }
}
]
Pane {
id: detailsPane
width: parent.width
anchors.bottom: parent.bottom
padding: 0
background: Rectangle {
color: Material.dialogColor
}
ColumnLayout {
id: rootLayout
width: parent.width
spacing: constants.paddingXLarge
Item { Layout.preferredWidth: 1; Layout.preferredHeight: 1 }
RowLayout {
Layout.fillWidth: true
FlatButton {
text: qsTr('More details')
Layout.fillWidth: true
Layout.preferredWidth: 1
enabled: app.stack.currentItem.objectName != 'WalletDetails'
onClicked: {
root.close()
app.stack.pushOnRoot(Qt.resolvedUrl('WalletDetails.qml'))
}
}
FlatButton {
text: qsTr('Switch wallet')
Layout.fillWidth: true
icon.source: '../../icons/file.png'
Layout.preferredWidth: 1
enabled: app.stack.currentItem.objectName != 'Wallets'
onClicked: {
root.close()
app.stack.pushOnRoot(Qt.resolvedUrl('Wallets.qml'))
}
}
}
}
}
property string formattedTotalBalance
property string formattedTotalBalanceFiat
function setBalances() {
root.formattedTotalBalance = Config.formatSats(Daemon.currentWallet.totalBalance)
if (Daemon.fx.enabled) {
root.formattedTotalBalanceFiat = Daemon.fx.fiatValue(Daemon.currentWallet.totalBalance, false)
}
}
// instead of all these explicit connections, we should expose
// formatted balances directly as a property
Connections {
target: Config
function onBaseUnitChanged() { setBalances() }
function onThousandsSeparatorChanged() { setBalances() }
}
Connections {
target: Daemon
function onWalletLoaded() { setBalances() }
}
Connections {
target: Daemon.fx
function onEnabledUpdated() { setBalances() }
function onQuotesUpdated() { setBalances() }
}
Connections {
target: Daemon.currentWallet
function onBalanceChanged() {
setBalances()
}
}
}
+22 -19
View File
@@ -32,7 +32,6 @@ Pane {
ColumnLayout {
Layout.fillWidth: true
Layout.margins: constants.paddingLarge
Heading {
text: qsTr('Wallets')
@@ -42,9 +41,9 @@ Pane {
id: detailsFrame
Layout.fillWidth: true
Layout.fillHeight: true
verticalPadding: 0
verticalPadding: bg.lineWidth
horizontalPadding: 0
background: PaneInsetBackground {}
background: PaneInsetBackground { id: bg; vertical: false }
ElListView {
id: listview
@@ -117,27 +116,31 @@ Pane {
}
FlatButton {
ButtonContainer {
Layout.fillWidth: true
text: qsTr('Create Wallet')
icon.source: '../../icons/add.png'
onClicked: {
if (Daemon.availableWallets.rowCount() > 0 && Config.walletShouldUseSinglePassword
&& (!Daemon.singlePassword || Daemon.numWalletsWithPassword(Daemon.singlePassword) < 1)) {
// if the user has wallets but hasn't unlocked any wallet yet force them to do so.
// this ensures they know at least one wallets password and can complete the wizard
// where they will need to enter the password of an existing wallet.
var dialog = app.messageDialog.createObject(app, {
title: qsTr('Wallet unlock required'),
text: qsTr("You have to unlock any existing wallet first before creating a new wallet."),
})
dialog.open()
} else {
rootItem.createWallet()
FlatButton {
Layout.fillWidth: true
text: qsTr('Create Wallet')
icon.source: '../../icons/add.png'
onClicked: {
if (Daemon.availableWallets.rowCount() > 0 && Config.walletShouldUseSinglePassword
&& (!Daemon.singlePassword || Daemon.numWalletsWithPassword(Daemon.singlePassword) < 1)) {
// if the user has wallets but hasn't unlocked any wallet yet force them to do so.
// this ensures they know at least one wallets password and can complete the wizard
// where they will need to enter the password of an existing wallet.
var dialog = app.messageDialog.createObject(app, {
title: qsTr('Wallet unlock required'),
text: qsTr("You have to unlock any existing wallet first before creating a new wallet."),
})
dialog.open()
} else {
rootItem.createWallet()
}
}
}
}
}
property color navigationBarBackgroundColor: constants.highlightBackground
Connections {
target: Daemon
@@ -16,7 +16,7 @@ TextField {
regularExpression: msatPrecision ? Config.btcAmountRegexMsat : Config.btcAmountRegex
}
property Amount textAsSats
property var textAsSats
onTextChanged: {
textAsSats = Config.unitsToSats(amount.text)
if (fiatfield.activeFocus)
@@ -7,11 +7,22 @@ Container {
id: root
property bool showSeparator: true
property color separatorColor: constants.darkerBackground
property Component headerComponent: null
property var _contentRootItem
property var _headerItem
property Item _layout
background: Rectangle {
color: constants.highlightBackground
}
function fillContentItem() {
var contentRoot = containerLayout.createObject(root)
var outerLayout = rootLayout.createObject(root)
if (headerComponent != null)
_headerItem = headerComponent.createObject(outerLayout)
var contentRoot = containerLayout.createObject(outerLayout)
contentRoot.children.length = 0 // empty array
let total = contentChildren.length
@@ -32,7 +43,8 @@ Container {
contentRoot.children.push(button)
}
contentItem = contentRoot
contentItem = outerLayout //contentRoot
_contentRootItem = contentRoot
}
// override this function to dynamically add buttons.
@@ -43,6 +55,13 @@ Container {
fillContentItem()
}
Component {
id: rootLayout
ColumnLayout {
spacing: 0
}
}
Component {
id: containerLayout
RowLayout {
@@ -59,7 +78,7 @@ Container {
Layout.preferredWidth: showSeparator ? 2 : 0
Layout.preferredHeight: pheight
Layout.alignment: Qt.AlignVCenter
color: constants.darkerBackground
color: root.separatorColor
Component.onCompleted: {
// create binding here, we need to be able to have stable ref master_idx
visible = Qt.binding(function() {
@@ -74,3 +93,4 @@ Container {
}
}
@@ -6,11 +6,11 @@ import QtQuick.Controls.Material
import org.electrum 1.0
Item {
property Amount capacity
property Amount localCapacity
property Amount remoteCapacity
property Amount canSend
property Amount canReceive
property var capacity // type: Amount
property var localCapacity // type: Amount
property var remoteCapacity // type: Amount
property var canSend // type: Amount
property var canReceive // type: Amount
property bool frozenForSending: false
property bool frozenForReceiving: false
@@ -0,0 +1,19 @@
import QtQuick
import QtQuick.Layouts
ButtonContainer {
id: root
separatorColor: constants.darkerDialogBackground
background: Rectangle {
color: "transparent"
}
headerComponent: Component {
Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: 2
Layout.leftMargin: constants.paddingSmall
Layout.rightMargin: constants.paddingSmall
color: root.separatorColor
}
}
}
@@ -0,0 +1,5 @@
import QtQuick
TextHighlightPane {
backgroundColor: constants.darkerDialogBackground
}
@@ -17,7 +17,7 @@ Dialog {
property bool _wasOpened: false
// Add bottom padding for Android navigation bar if needed
bottomPadding: needsSystemBarPadding ? app.navigationBarHeight : 0
bottomPadding: needsSystemBarPadding && app.keyboardFreeZone.state != 'visible' ? app.navigationBarHeight : 0
// called to finally close dialog after checks by onClosing handler in main.qml
function doClose() {
@@ -106,10 +106,10 @@ Dialog {
Rectangle {
Layout.fillWidth: true
Layout.leftMargin: constants.paddingXXSmall
Layout.rightMargin: constants.paddingXXSmall
height: 1
color: Qt.rgba(0,0,0,0.5)
Layout.leftMargin: constants.paddingSmall
Layout.rightMargin: constants.paddingSmall
Layout.preferredHeight: 2
color: constants.darkerDialogBackground
}
}
@@ -9,6 +9,7 @@ TabButton {
checkable: false
property bool textUnderIcon: true
property bool pressAndHoldIndicator: false
font.pixelSize: constants.fontSizeSmall
icon.width: constants.iconSizeMedium
@@ -25,4 +26,45 @@ TabButton {
font: control.font
color: !control.enabled ? control.Material.hintTextColor : control.down || control.checked ? control.Material.accentColor : control.Material.foreground
}
Rectangle {
id: indicator
anchors.top: control.top
anchors.horizontalCenter: control.horizontalCenter
width: 0
opacity: 0
height: 3
color: control.Material.accentColor
states: State {
name: 'pressing'
when: pressAndHoldIndicator && control.pressed
PropertyChanges {
target: indicator
width: control.width
opacity: 1
}
}
transitions: Transition {
to: 'pressing'
SequentialAnimation {
PauseAnimation {
duration: 200
}
ParallelAnimation {
NumberAnimation {
target: indicator
property: "width"
duration: 600
}
NumberAnimation {
target: indicator
property: "opacity"
duration: 600
}
}
}
}
}
}
@@ -6,7 +6,7 @@ import QtQuick.Controls.Material
import org.electrum 1.0
GridLayout {
required property Amount amount
required property var amount // type: Amount
property bool showAlt: true
property bool singleLine: true
property bool valid: true
@@ -35,7 +35,7 @@ ElDialog {
implicitHeight: rootLayout.height + topPadding + bottomPadding
padding: constants.paddingLarge
background: Rectangle {
color: constants.lighterBackground
color: constants.highlightBackground
}
ColumnLayout {
id: rootLayout
@@ -3,25 +3,33 @@ import QtQuick.Controls.Material
Rectangle {
property color baseColor: Material.background
property bool vertical: true
property bool horizontal: true
property int lineWidth: 2
Rectangle {
anchors { left: parent.left; top: parent.top; right: parent.right }
height: 1
height: lineWidth
color: Qt.darker(baseColor, 1.50)
visible: horizontal
}
Rectangle {
anchors { left: parent.left; top: parent.top; bottom: parent.bottom }
width: 1
width: lineWidth
color: Qt.darker(baseColor, 1.50)
visible: vertical
}
Rectangle {
anchors { left: parent.left; bottom: parent.bottom; right: parent.right }
height: 1
height: lineWidth
color: Qt.lighter(baseColor, 1.50)
visible: horizontal
}
Rectangle {
anchors { right: parent.right; top: parent.top; bottom: parent.bottom }
width: 1
width: lineWidth
color: Qt.lighter(baseColor, 1.50)
visible: vertical
}
color: Qt.darker(baseColor, 1.15)
}
@@ -7,6 +7,7 @@ RowLayout {
property alias text: password_tf.text
property alias tf: password_tf
property alias echoMode: password_tf.echoMode
property alias placeholderText: password_tf.placeholderText
property bool showReveal: true
signal accepted
@@ -53,68 +53,62 @@ Item {
model: proxy_type_map
}
GridLayout {
columns: 2
ColumnLayout {
// columns: 2
Layout.fillWidth: true
spacing: constants.paddingSmall
Label {
text: qsTr("Address")
enabled: address.enabled
}
RowLayout {
Layout.fillWidth: true
Layout.rightMargin: constants.paddingLarge
TextField {
id: address
enabled: proxy_enabled_cb.checked
inputMethodHints: Qt.ImhNoPredictiveText
TextField {
id: address
Layout.fillWidth: true
enabled: proxy_enabled_cb.checked
inputMethodHints: Qt.ImhNoPredictiveText
placeholderText: qsTr("Address")
}
TextField {
id: port
Layout.fillWidth: true
enabled: proxy_enabled_cb.checked
inputMethodHints: Qt.ImhDigitsOnly
placeholderText: qsTr("Port")
}
}
Label {
text: qsTr("Port")
enabled: port.enabled
}
TextField {
id: port
enabled: proxy_enabled_cb.checked
inputMethodHints: Qt.ImhDigitsOnly
}
Label {
text: qsTr("Username")
Layout.topMargin: constants.paddingLarge
text: qsTr("Authentication")
enabled: username_tf.enabled
}
TextField {
id: username_tf
Layout.fillWidth: true
Layout.rightMargin: constants.paddingLarge
enabled: proxy_enabled_cb.checked
inputMethodHints: Qt.ImhNoPredictiveText
}
Label {
text: qsTr("Password")
enabled: password_tf.enabled
placeholderText: qsTr("Username")
}
PasswordField {
id: password_tf
enabled: proxy_enabled_cb.checked
placeholderText: qsTr("Password")
}
}
Pane {
Button {
Layout.alignment: Qt.AlignHCenter
Layout.topMargin: constants.paddingLarge
padding: 0
background: Rectangle {
color: constants.darkerDialogBackground
}
FlatButton {
enabled: proxy_enabled_cb.checked && !_probing
text: qsTr('Detect Tor proxy')
onClicked: {
_probing = true
Network.probeTor()
}
enabled: proxy_enabled_cb.checked && !_probing
text: qsTr('Detect Tor proxy')
onClicked: {
_probing = true
Network.probeTor()
}
}
@@ -19,6 +19,10 @@ Pane {
kbd.keyEvent(keycode, key)
}
background: Rectangle {
color: constants.darkerDialogBackground
}
FlatButton {
anchors.fill: parent
@@ -35,10 +35,11 @@ Pane {
TextArea {
id: seedtextarea
Layout.fillWidth: true
Layout.minimumHeight: fontMetrics.height * 3 + topPadding + bottomPadding
Layout.minimumHeight: fontMetrics.lineSpacing * 3 + topPadding + bottomPadding
rightPadding: constants.paddingLarge
leftPadding: constants.paddingLarge
bottomPadding: constants.paddingXLarge
wrapMode: TextInput.WordWrap
font.bold: true
@@ -47,8 +48,9 @@ Pane {
inputMethodHints: Qt.ImhSensitiveData | Qt.ImhLowercaseOnly | Qt.ImhNoPredictiveText
readOnly: AppController.isAndroid()
background: Rectangle {
color: constants.darkerBackground
Component.onCompleted: {
background.filled = true
background.fillColor = constants.seedTextAreaBackground
}
onTextChanged: {
@@ -66,16 +68,19 @@ Pane {
Rectangle {
anchors.fill: contentText
color: root.indicatorValid ? 'green' : 'red'
border.color: Material.accentColor
radius: 2
radius: 3
}
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
anchors.rightMargin: constants.paddingXXSmall
anchors.bottomMargin: constants.paddingXXSmall
leftPadding: root.indicatorText != '' ? constants.paddingMedium : 0
rightPadding: root.indicatorText != '' ? constants.paddingMedium : 0
topPadding: root.indicatorText != '' ? constants.paddingXXSmall/2 : 0
bottomPadding: root.indicatorText != '' ? constants.paddingXXSmall/2 : 0
font.bold: false
font.pixelSize: constants.fontSizeSmall
}
@@ -99,7 +104,7 @@ Pane {
Layout.margins: constants.paddingXXSmall
width: suggestionLabel.width
height: suggestionLabel.height
color: constants.lighterBackground
color: constants.darkerDialogBackground
radius: constants.paddingXXSmall
Label {
id: suggestionLabel
@@ -127,7 +132,7 @@ Pane {
Layout.fillWidth: true
Layout.preferredHeight: kbd.width / 1.75
visible: !root.readOnly
onKeyEvent: {
onKeyEvent: (keycode, text) => {
if (keycode == Qt.Key_Backspace) {
if (seedtextarea.text.length > 0)
seedtextarea.text = seedtextarea.text.substring(0, seedtextarea.text.length-1)
@@ -43,7 +43,7 @@ Item {
HelpButton {
Layout.alignment: Qt.AlignRight
heading: qsTr('Connection mode')+':'
heading: qsTr('Connection mode') + ':'
helptext: Config.getTranslatedMessage('MSG_CONNECTMODE_SERVER_HELP') + '<br/><br/>' +
Config.getTranslatedMessage('MSG_CONNECTMODE_NODES_HELP') + '<ul>' +
'<li><b>' + Config.getTranslatedMessage('MSG_CONNECTMODE_AUTOCONNECT') +
@@ -56,39 +56,32 @@ Item {
}
}
Label {
text: qsTr("Server")
enabled: address_tf.enabled
}
TextHighlightPane {
TextField {
id: address_tf
Layout.fillWidth: true
TextField {
id: address_tf
enabled: server_connect_mode_cb.currentValue != ServerConnectModeComboBox.Mode.Autoconnect
width: parent.width
inputMethodHints: Qt.ImhNoPredictiveText
enabled: server_connect_mode_cb.currentValue != ServerConnectModeComboBox.Mode.Autoconnect
inputMethodHints: Qt.ImhNoPredictiveText
placeholderText: qsTr('Server')
property bool valid: true
property bool valid: true
function validate() {
if (!enabled) {
valid = true
return
}
valid = Network.isValidServerAddress(address_tf.text)
function validate() {
if (!enabled) {
valid = true
return
}
valid = Network.isValidServerAddress(address_tf.text)
}
onTextChanged: validate()
onEnabledChanged: validate()
onTextChanged: validate()
onEnabledChanged: validate()
Rectangle {
anchors.fill: parent
color: "red"
opacity: 0.2
visible: !parent.valid
}
Rectangle {
anchors.fill: parent
color: "red"
opacity: 0.2
visible: !parent.valid
}
}
@@ -6,7 +6,7 @@ import QtQuick.Controls.Material
Pane {
padding: constants.paddingSmall
property color backgroundColor: Qt.lighter(Material.background, 1.15)
property color backgroundColor: constants.highlightBackground
property color borderColor: 'transparent'
background: Rectangle {
+13 -10
View File
@@ -7,7 +7,6 @@ import QtQuick.Controls.Material.impl
import QtQuick.Window
import QtQml
import QtMultimedia
import org.electrum 1.0
@@ -37,6 +36,7 @@ ApplicationWindow
property alias stack: mainStackView
property alias keyboardFreeZone: _keyboardFreeZone
property alias infobanner: _infobanner
property color _navigationBarBackgroundColor: 'transparent'
property string pendingIntent: ""
@@ -128,7 +128,7 @@ ApplicationWindow
background: Rectangle {
implicitHeight: 48
color: Material.dialogColor
color: constants.dialogColor
layer.enabled: true
layer.effect: ElevationEffect {
@@ -288,13 +288,21 @@ ApplicationWindow
mainStackView.clear()
mainStackView.push(Qt.resolvedUrl(item_url))
}
function updateStylingFromItem(item) {
_navigationBarBackgroundColor = item && 'navigationBarBackgroundColor' in item
? item.navigationBarBackgroundColor
: 'transparent'
}
onCurrentItemChanged: updateStylingFromItem(currentItem)
}
// Add bottom padding for navigation bar on Android when UI is edge-to-edge
Item {
visible: app.navigationBarHeight > 0
visible: app.navigationBarHeight > 0 && _keyboardFreeZone.state != 'visible'
Layout.fillWidth: true
Layout.preferredHeight: app.navigationBarHeight
Rectangle { anchors.fill: parent; color: _navigationBarBackgroundColor }
}
}
@@ -450,12 +458,6 @@ ApplicationWindow
onFinished: destroy()
}
}
Component {
id: _qtScanDialog
ScanDialog {
onClosed: destroy()
}
}
Component {
id: crashDialog
@@ -533,7 +535,8 @@ ApplicationWindow
if (AppController.isAndroid()) {
app.scanDialog = _scanDialog
} else {
app.scanDialog = _qtScanDialog
// for running on Desktop. uses QtMultimedia.
app.scanDialog = Qt.createComponent('ScanDialog.qml')
}
function continueWithServerConnection() {
@@ -30,6 +30,7 @@ WizardComponent {
InfoTextArea {
Layout.fillWidth: true
Layout.bottomMargin: constants.paddingLarge
backgroundColor: constants.darkerDialogBackground
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.')
@@ -42,6 +43,7 @@ WizardComponent {
SeedTextArea {
id: confirm
Layout.fillWidth: true
Layout.topMargin: constants.paddingSmall
placeholderText: qsTr('Enter your seed')
onTextChanged: checkValid()
}
@@ -39,7 +39,7 @@ WizardComponent {
wrapMode: Text.Wrap
}
TextHighlightPane {
DialogHighlightPane {
Layout.fillWidth: true
visible: cosigner
@@ -47,6 +47,7 @@ WizardComponent {
InfoTextArea {
id: warningtext
Layout.fillWidth: true
backgroundColor: constants.darkerDialogBackground
iconStyle: InfoTextArea.IconStyle.Warn
}
@@ -61,6 +61,7 @@ WizardComponent {
id: validationtext
Layout.fillWidth: true
Layout.columnSpan: 2
backgroundColor: constants.darkerDialogBackground
visible: text
iconStyle: InfoTextArea.IconStyle.Error
}
@@ -71,7 +71,7 @@ WizardComponent {
wrapMode: Text.Wrap
}
TextHighlightPane {
DialogHighlightPane {
Layout.fillWidth: true
visible: cosigner
@@ -159,7 +159,6 @@ WizardComponent {
icon.source: '../../../icons/qrcode.png'
icon.height: constants.iconSizeMedium
icon.width: constants.iconSizeMedium
scale: 1.2
onClicked: {
var dialog = app.scanDialog.createObject(app, {
hint: cosigner
@@ -117,7 +117,7 @@ WizardComponent {
wrapMode: Text.Wrap
}
TextHighlightPane {
DialogHighlightPane {
Layout.columnSpan: 2
Layout.fillWidth: true
@@ -169,6 +169,7 @@ WizardComponent {
ComboBox {
id: seed_variant_cb
visible: !is2fa
textRole: 'text'
@@ -188,13 +189,16 @@ WizardComponent {
id: infotext
Layout.fillWidth: true
Layout.columnSpan: 2
Layout.bottomMargin: constants.paddingLarge
Layout.topMargin: constants.paddingLarge
compact: true
backgroundColor: constants.darkerDialogBackground
}
SeedTextArea {
id: seedtext
Layout.fillWidth: true
Layout.columnSpan: 2
Layout.topMargin: constants.paddingLarge
placeholderText: cosigner ? qsTr('Enter cosigner seed') : qsTr('Enter your seed')
@@ -27,8 +27,10 @@ WizardComponent {
ColumnLayout {
width: parent.width
height: parent.height
InfoTextArea {
Layout.preferredWidth: parent.width
backgroundColor: constants.darkerDialogBackground
text: qsTr('Enter a list of Bitcoin addresses (this will create a watching-only wallet), or a list of private keys.')
}
@@ -67,7 +69,6 @@ WizardComponent {
icon.source: '../../../icons/qrcode.png'
icon.height: constants.iconSizeMedium
icon.width: constants.iconSizeMedium
scale: 1.2
onClicked: {
var dialog = app.scanDialog.createObject(app, {
hint: bitcoin.isAddressList(import_ta.text)
@@ -41,6 +41,7 @@ WizardComponent {
InfoTextArea {
Layout.preferredWidth: parent.width
backgroundColor: constants.darkerDialogBackground
text: qsTr('Choose the number of participants, and the number of signatures needed to unlock funds in your wallet.')
}
@@ -161,19 +161,19 @@ WizardComponent {
InfoTextArea {
Layout.fillWidth: true
Layout.topMargin: constants.paddingMedium
Layout.bottomMargin: constants.paddingMedium
compact: true
backgroundColor: constants.darkerDialogBackground
text: qsTr('You can override the suggested derivation path.') + ' ' +
qsTr('If you are not sure what this is, leave this field unchanged.')
}
Label {
text: qsTr('Derivation path')
}
TextField {
id: derivationpathtext
Layout.fillWidth: true
Layout.leftMargin: constants.paddingMedium
inputMethodHints: Qt.ImhNoPredictiveText
placeholderText: qsTr('Derivation path')
onTextChanged: validate()
}
@@ -181,43 +181,36 @@ WizardComponent {
InfoTextArea {
id: validationtext
Layout.fillWidth: true
backgroundColor: constants.darkerDialogBackground
visible: text
iconStyle: InfoTextArea.IconStyle.Error
}
Pane {
Button {
Layout.alignment: Qt.AlignHCenter
Layout.topMargin: constants.paddingLarge
padding: 0
visible: !isMultisig
background: Rectangle {
color: Qt.lighter(Material.dialogColor, 1.5)
}
FlatButton {
text: qsTr('Detect Existing Accounts')
onClicked: {
var dialog = bip39recoveryDialog.createObject(mainLayout, {
walletType: wizard_data['wallet_type'],
seed: wizard_data['seed'],
seedExtraWords: wizard_data['seed_extra_words']
})
dialog.accepted.connect(function () {
// select matching script type button and set derivation path
for (var i = 0; i < scripttypegroup.buttons.length; i++) {
var btn = scripttypegroup.buttons[i]
if (btn.visible && btn.scripttype == dialog.scriptType) {
btn.checked = true
derivationpathtext.text = dialog.derivationPath
return
}
text: qsTr('Detect Existing Accounts')
onClicked: {
var dialog = bip39recoveryDialog.createObject(mainLayout, {
walletType: wizard_data['wallet_type'],
seed: wizard_data['seed'],
seedExtraWords: wizard_data['seed_extra_words']
})
dialog.accepted.connect(function () {
// select matching script type button and set derivation path
for (var i = 0; i < scripttypegroup.buttons.length; i++) {
var btn = scripttypegroup.buttons[i]
if (btn.visible && btn.scripttype == dialog.scriptType) {
btn.checked = true
derivationpathtext.text = dialog.derivationPath
return
}
})
dialog.open()
}
}
})
dialog.open()
}
}
}
}
@@ -1,49 +0,0 @@
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls
import org.electrum 1.0
import "../controls"
WizardComponent {
valid: true
property string masterPubkey: wizard_data['multisig_master_pubkey']
ColumnLayout {
width: parent.width
Label {
text: qsTr('Here is your master public key. Please share it with your cosigners')
Layout.fillWidth: true
wrapMode: Text.Wrap
}
TextHighlightPane {
Layout.fillWidth: true
RowLayout {
width: parent.width
Label {
Layout.fillWidth: true
text: masterPubkey
font.pixelSize: constants.fontSizeMedium
font.family: FixedFont
wrapMode: Text.Wrap
}
ToolButton {
icon.source: '../../../icons/share.png'
icon.color: 'transparent'
onClicked: {
var dialog = app.genericShareDialog.createObject(app,
{ title: qsTr('Master public key'), text: masterPubkey }
)
dialog.open()
}
}
}
}
}
}
@@ -45,12 +45,14 @@ WizardComponent {
Label {
Layout.fillWidth: true
text: !enforceExistingPassword ? qsTr('Enter password') : qsTr('Enter existing password')
Layout.bottomMargin: constants.paddingSmall
text: !enforceExistingPassword ? qsTr('Enter a password to secure access to your wallet') : qsTr('Enter your existing wallet password')
wrapMode: Text.Wrap
}
PasswordField {
id: password1
placeholderText: qsTr('Enter password')
onTextChanged: {
if (enforceExistingPassword) {
root.passwordMatchesAnyExisting = false
@@ -59,16 +61,12 @@ WizardComponent {
}
}
Label {
text: qsTr('Enter password (again)')
visible: !enforceExistingPassword
}
PasswordField {
id: password2
showReveal: false
echoMode: password1.echoMode
visible: !enforceExistingPassword
placeholderText: qsTr('Enter password (again)')
}
RowLayout {
@@ -100,12 +98,14 @@ WizardComponent {
text: qsTr('Passwords don\'t match')
visible: (password1.text != password2.text) && !enforceExistingPassword
iconStyle: InfoTextArea.IconStyle.Warn
backgroundColor: constants.darkerDialogBackground
}
InfoTextArea {
Layout.alignment: Qt.AlignCenter
text: qsTr('Password too short')
visible: (password1.text == password2.text) && !valid && !enforceExistingPassword
visible: (password1.text == password2.text) && password1.text != '' && !valid && !enforceExistingPassword
iconStyle: InfoTextArea.IconStyle.Warn
backgroundColor: constants.darkerDialogBackground
}
InfoTextArea {
Layout.alignment: Qt.AlignCenter
@@ -116,6 +116,7 @@ WizardComponent {
qsTr("Creating new wallets with different passwords is not supported.")
].join("\n")
iconStyle: InfoTextArea.IconStyle.Info
backgroundColor: constants.darkerDialogBackground
}
InfoTextArea {
Layout.alignment: Qt.AlignCenter
@@ -123,6 +124,13 @@ WizardComponent {
visible: password1.text != "" && !valid && enforceExistingPassword
text: qsTr('Password does not match any existing wallets password.')
iconStyle: InfoTextArea.IconStyle.Warn
backgroundColor: constants.darkerDialogBackground
}
Item {
Layout.preferredWidth: 1
Layout.fillHeight: true
}
}
}
@@ -107,7 +107,7 @@ ElDialog {
spacing: 0
// root Item in Wizard, capture back button here and delegate to main
Keys.onReleased: {
Keys.onReleased: (event) => {
if (event.key == Qt.Key_Back) {
console.log("Back button within wizard")
app.close() // this handles unwind of dialogs/stack
@@ -159,12 +159,13 @@ ElDialog {
}
}
ButtonContainer {
DialogButtonContainer {
Layout.fillWidth: true
FlatButton {
Layout.fillWidth: true
Layout.preferredWidth: 1
Layout.preferredHeight: constants.fingerWidth
visible: pages.currentIndex == 0
text: qsTr("Cancel")
onClicked: wizard.doReject()
@@ -172,6 +173,7 @@ ElDialog {
FlatButton {
Layout.fillWidth: true
Layout.preferredWidth: 1
Layout.preferredHeight: constants.fingerWidth
visible: pages.currentIndex > 0
text: qsTr('Back')
onClicked: pages.prev()
@@ -179,6 +181,7 @@ ElDialog {
FlatButton {
Layout.fillWidth: true
Layout.preferredWidth: 1
Layout.preferredHeight: constants.fingerWidth
text: qsTr("Next")
visible: !pages.lastpage
enabled: pages.pagevalid
@@ -188,6 +191,7 @@ ElDialog {
id: finishButton
Layout.fillWidth: true
Layout.preferredWidth: 1
Layout.preferredHeight: constants.fingerWidth
text: qsTr("Finish")
visible: pages.lastpage
enabled: pages.pagevalid
+4 -3
View File
@@ -1,4 +1,4 @@
from PyQt6.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject
from PyQt6.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject, QVariant
from electrum.logging import get_logger
from electrum.util import UserFacingException
@@ -35,12 +35,13 @@ class QEAddressDetails(AuthMixin, QObject):
self._historyModel = None
walletChanged = pyqtSignal()
@pyqtProperty(QEWallet, notify=walletChanged)
def wallet(self):
@pyqtProperty(QVariant, notify=walletChanged)
def wallet(self) -> QEWallet:
return self._wallet
@wallet.setter
def wallet(self, wallet: QEWallet):
assert isinstance(wallet, QEWallet)
if self._wallet != wallet:
self._wallet = wallet
self.walletChanged.emit()
+3 -2
View File
@@ -2,7 +2,7 @@ import threading
from enum import IntEnum
from typing import Optional, TYPE_CHECKING
from PyQt6.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject, pyqtEnum
from PyQt6.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject, pyqtEnum, QVariant
from electrum.i18n import _
from electrum.gui import messages
@@ -61,12 +61,13 @@ class QEChannelDetails(AuthMixin, QObject, QtEventListener):
self.unregister_callbacks()
walletChanged = pyqtSignal()
@pyqtProperty(QEWallet, notify=walletChanged)
@pyqtProperty(QVariant, notify=walletChanged)
def wallet(self) -> QEWallet:
return self._wallet
@wallet.setter
def wallet(self, wallet: QEWallet):
assert wallet is None or isinstance(wallet, QEWallet)
if self._wallet != wallet:
self._wallet = wallet
self.walletChanged.emit()
+7 -3
View File
@@ -1,5 +1,6 @@
from PyQt6.QtCore import Qt, QAbstractListModel, QModelIndex
from PyQt6.QtCore import pyqtProperty, pyqtSignal, pyqtSlot
from typing import TYPE_CHECKING
from PyQt6.QtCore import Qt, QAbstractListModel, QModelIndex, pyqtProperty, pyqtSignal, pyqtSlot
from electrum.lnchannel import ChannelState
from electrum.lnutil import LOCAL, REMOTE
@@ -12,6 +13,9 @@ from electrum.gui.common_qt.util import qt_event_listener, QtEventListener
from .qetypes import QEAmount
from .qemodelfilter import QEFilterProxyModel
if TYPE_CHECKING:
from electrum.wallet import Abstract_Wallet
class QEChannelListModel(QAbstractListModel, QtEventListener):
_logger = get_logger(__name__)
@@ -27,7 +31,7 @@ class QEChannelListModel(QAbstractListModel, QtEventListener):
_network_signal = pyqtSignal(str, object)
def __init__(self, wallet, parent=None):
def __init__(self, wallet: 'Abstract_Wallet', parent=None):
super().__init__(parent)
self.wallet = wallet
self._channels = []
+7 -6
View File
@@ -4,7 +4,7 @@ from asyncio.exceptions import TimeoutError
from typing import Optional
import electrum_ecc as ecc
from PyQt6.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject
from PyQt6.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject, QVariant
from electrum.i18n import _
from electrum.gui import messages
@@ -14,7 +14,6 @@ from electrum.lntransport import extract_nodeid, ConnStringFormatError
from electrum.bitcoin import DummyAddress
from electrum.lnworker import hardcoded_trampoline_nodes
from electrum.logging import get_logger
from electrum.fee_policy import FeePolicy
from electrum.transaction import PartialTransaction
from .auth import AuthMixin, auth_protect
@@ -55,12 +54,13 @@ class QEChannelOpener(QObject, AuthMixin):
self._updating_max = False
walletChanged = pyqtSignal()
@pyqtProperty(QEWallet, notify=walletChanged)
def wallet(self):
@pyqtProperty(QVariant, notify=walletChanged)
def wallet(self) -> QEWallet:
return self._wallet
@wallet.setter
def wallet(self, wallet: QEWallet):
assert wallet is None or isinstance(wallet, QEWallet)
if self._wallet != wallet:
self._wallet = wallet
self.walletChanged.emit()
@@ -79,12 +79,13 @@ class QEChannelOpener(QObject, AuthMixin):
self.validate()
amountChanged = pyqtSignal()
@pyqtProperty(QEAmount, notify=amountChanged)
def amount(self):
@pyqtProperty(QVariant, notify=amountChanged)
def amount(self) -> QEAmount:
return self._amount
@amount.setter
def amount(self, amount: QEAmount):
assert amount is None or isinstance(amount, QEAmount)
if self._amount != amount:
self._amount.copyFrom(amount)
self.amountChanged.emit()
+7 -5
View File
@@ -4,7 +4,7 @@ from enum import IntEnum
from typing import Optional, Dict, Any, Tuple
from urllib.parse import urlparse
from PyQt6.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject, pyqtEnum, QTimer
from PyQt6.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject, pyqtEnum, QTimer, QVariant
from electrum.i18n import _
from electrum.logging import get_logger
@@ -111,12 +111,13 @@ class QEInvoice(QObject, QtEventListener):
self.determine_can_pay()
walletChanged = pyqtSignal()
@pyqtProperty(QEWallet, notify=walletChanged)
def wallet(self):
@pyqtProperty(QVariant, notify=walletChanged)
def wallet(self) -> QEWallet:
return self._wallet
@wallet.setter
def wallet(self, wallet: QEWallet):
assert wallet is None or isinstance(wallet, QEWallet)
if self._wallet != wallet:
self._wallet = wallet
self.walletChanged.emit()
@@ -153,12 +154,13 @@ class QEInvoice(QObject, QtEventListener):
self._amount.copyFrom(QEAmount(from_invoice=self._effectiveInvoice))
return self._amount
@pyqtProperty(QEAmount, notify=amountOverrideChanged)
def amountOverride(self):
@pyqtProperty(QVariant, notify=amountOverrideChanged)
def amountOverride(self) -> QEAmount:
return self._amountOverride
@amountOverride.setter
def amountOverride(self, new_amount: QEAmount):
assert new_amount is None or isinstance(new_amount, QEAmount)
self._logger.debug(f'set new override amount {repr(new_amount)}')
self._amountOverride.copyFrom(new_amount)
self.amountOverrideChanged.emit()

Some files were not shown because too many files have changed in this diff Show More