diff --git a/contrib/android/Dockerfile b/contrib/android/Dockerfile index d462bd4d2..73493413b 100644 --- a/contrib/android/Dockerfile +++ b/contrib/android/Dockerfile @@ -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 \ diff --git a/contrib/android/Readme.md b/contrib/android/Readme.md index e9ccf879b..6e348effd 100644 --- a/contrib/android/Readme.md +++ b/contrib/android/Readme.md @@ -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: diff --git a/contrib/android/buildozer_qml.spec b/contrib/android/buildozer_qml.spec index 454618176..a73fdc5b8 100644 --- a/contrib/android/buildozer_qml.spec +++ b/contrib/android/buildozer_qml.spec @@ -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 diff --git a/contrib/android/dl-ndk-ci.sh b/contrib/android/dl-ndk-ci.sh deleted file mode 100755 index 41b1922f2..000000000 --- a/contrib/android/dl-ndk-ci.sh +++ /dev/null @@ -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 diff --git a/contrib/android/p4a_recipes/android/__init__.py b/contrib/android/p4a_recipes/android/__init__.py new file mode 100644 index 000000000..17bd29ad2 --- /dev/null +++ b/contrib/android/p4a_recipes/android/__init__.py @@ -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() diff --git a/contrib/android/p4a_recipes/cffi/__init__.py b/contrib/android/p4a_recipes/cffi/__init__.py index c96c7ac51..a5bbf2b32 100644 --- a/contrib/android/p4a_recipes/cffi/__init__.py +++ b/contrib/android/p4a_recipes/cffi/__init__.py @@ -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() diff --git a/contrib/android/p4a_recipes/hostpython3/__init__.py b/contrib/android/p4a_recipes/hostpython3/__init__.py index a9a1be3eb..a4a63d7bd 100644 --- a/contrib/android/p4a_recipes/hostpython3/__init__.py +++ b/contrib/android/p4a_recipes/hostpython3/__init__.py @@ -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() diff --git a/contrib/android/p4a_recipes/openssl/__init__.py b/contrib/android/p4a_recipes/openssl/__init__.py index fdbb7d662..062b18e58 100644 --- a/contrib/android/p4a_recipes/openssl/__init__.py +++ b/contrib/android/p4a_recipes/openssl/__init__.py @@ -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 == [] diff --git a/contrib/android/p4a_recipes/packaging/__init__.py b/contrib/android/p4a_recipes/packaging/__init__.py index a8f225ae2..b16d67d47 100644 --- a/contrib/android/p4a_recipes/packaging/__init__.py +++ b/contrib/android/p4a_recipes/packaging/__init__.py @@ -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() diff --git a/contrib/android/p4a_recipes/pycryptodomex/__init__.py b/contrib/android/p4a_recipes/pycryptodomex/__init__.py index 0e0a580bf..0491968e5 100644 --- a/contrib/android/p4a_recipes/pycryptodomex/__init__.py +++ b/contrib/android/p4a_recipes/pycryptodomex/__init__.py @@ -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() diff --git a/contrib/android/p4a_recipes/pyjnius/__init__.py b/contrib/android/p4a_recipes/pyjnius/__init__.py index 16a052e0e..267f5d9a3 100644 --- a/contrib/android/p4a_recipes/pyjnius/__init__.py +++ b/contrib/android/p4a_recipes/pyjnius/__init__.py @@ -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() diff --git a/contrib/android/p4a_recipes/pyparsing/__init__.py b/contrib/android/p4a_recipes/pyparsing/__init__.py index 04f515dbc..c6a3e9e1e 100644 --- a/contrib/android/p4a_recipes/pyparsing/__init__.py +++ b/contrib/android/p4a_recipes/pyparsing/__init__.py @@ -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() diff --git a/contrib/android/p4a_recipes/pyqt6/__init__.py b/contrib/android/p4a_recipes/pyqt6/__init__.py index 37b2a2119..1f08245d2 100644 --- a/contrib/android/p4a_recipes/pyqt6/__init__.py +++ b/contrib/android/p4a_recipes/pyqt6/__init__.py @@ -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() diff --git a/contrib/android/p4a_recipes/pyqt6sip/__init__.py b/contrib/android/p4a_recipes/pyqt6sip/__init__.py index 301c15762..dea22376f 100644 --- a/contrib/android/p4a_recipes/pyqt6sip/__init__.py +++ b/contrib/android/p4a_recipes/pyqt6sip/__init__.py @@ -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() diff --git a/contrib/android/p4a_recipes/pyqt_builder/__init__.py b/contrib/android/p4a_recipes/pyqt_builder/__init__.py index 6b6a67488..8fa65576d 100644 --- a/contrib/android/p4a_recipes/pyqt_builder/__init__.py +++ b/contrib/android/p4a_recipes/pyqt_builder/__init__.py @@ -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() diff --git a/contrib/android/p4a_recipes/python3/__init__.py b/contrib/android/p4a_recipes/python3/__init__.py index 6fc9d51e8..11cf39546 100644 --- a/contrib/android/p4a_recipes/python3/__init__.py +++ b/contrib/android/p4a_recipes/python3/__init__.py @@ -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() diff --git a/contrib/android/p4a_recipes/qt6/__init__.py b/contrib/android/p4a_recipes/qt6/__init__.py index 1a91e0bf3..dcb443d9a 100644 --- a/contrib/android/p4a_recipes/qt6/__init__.py +++ b/contrib/android/p4a_recipes/qt6/__init__.py @@ -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() diff --git a/contrib/android/p4a_recipes/setuptools/__init__.py b/contrib/android/p4a_recipes/setuptools/__init__.py deleted file mode 100644 index 10a26f398..000000000 --- a/contrib/android/p4a_recipes/setuptools/__init__.py +++ /dev/null @@ -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() diff --git a/contrib/android/p4a_recipes/sip/__init__.py b/contrib/android/p4a_recipes/sip/__init__.py index d1aea65e4..af6fdffb4 100644 --- a/contrib/android/p4a_recipes/sip/__init__.py +++ b/contrib/android/p4a_recipes/sip/__init__.py @@ -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() diff --git a/electrum/gui/icons/closebutton.png b/electrum/gui/icons/closebutton.png index 349241801..ecd8a0de4 100644 Binary files a/electrum/gui/icons/closebutton.png and b/electrum/gui/icons/closebutton.png differ diff --git a/electrum/gui/icons/copy_bw.png b/electrum/gui/icons/copy_bw.png index 739edbecb..50d75729c 100644 Binary files a/electrum/gui/icons/copy_bw.png and b/electrum/gui/icons/copy_bw.png differ diff --git a/electrum/gui/icons/qrcode.png b/electrum/gui/icons/qrcode.png index 41a84aa1d..3c1bf8b04 100644 Binary files a/electrum/gui/icons/qrcode.png and b/electrum/gui/icons/qrcode.png differ diff --git a/electrum/gui/icons/qrcode_white.png b/electrum/gui/icons/qrcode_white.png index 23ea91655..9c675be77 100644 Binary files a/electrum/gui/icons/qrcode_white.png and b/electrum/gui/icons/qrcode_white.png differ diff --git a/electrum/gui/qml/components/AddressDetails.qml b/electrum/gui/qml/components/AddressDetails.qml index b631e4b6b..eaf4c610e 100644 --- a/electrum/gui/qml/components/AddressDetails.qml +++ b/electrum/gui/qml/components/AddressDetails.qml @@ -329,6 +329,7 @@ Pane { } } } + property color navigationBarBackgroundColor: constants.highlightBackground AddressDetails { id: addressdetails diff --git a/electrum/gui/qml/components/Addresses.qml b/electrum/gui/qml/components/Addresses.qml index aecd75415..71d441121 100644 --- a/electrum/gui/qml/components/Addresses.qml +++ b/electrum/gui/qml/components/Addresses.qml @@ -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 diff --git a/electrum/gui/qml/components/BIP39RecoveryDialog.qml b/electrum/gui/qml/components/BIP39RecoveryDialog.qml index 6910d3de8..97e9d0a47 100644 --- a/electrum/gui/qml/components/BIP39RecoveryDialog.qml +++ b/electrum/gui/qml/components/BIP39RecoveryDialog.qml @@ -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 diff --git a/electrum/gui/qml/components/BalanceDetails.qml b/electrum/gui/qml/components/BalanceDetails.qml index 49b92a462..03efe73e7 100644 --- a/electrum/gui/qml/components/BalanceDetails.qml +++ b/electrum/gui/qml/components/BalanceDetails.qml @@ -233,8 +233,8 @@ Pane { } } - } + property color navigationBarBackgroundColor: constants.highlightBackground Component { id: openChannelDialog diff --git a/electrum/gui/qml/components/ChannelDetails.qml b/electrum/gui/qml/components/ChannelDetails.qml index ab18e6e45..d43e1efdd 100644 --- a/electrum/gui/qml/components/ChannelDetails.qml +++ b/electrum/gui/qml/components/ChannelDetails.qml @@ -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 diff --git a/electrum/gui/qml/components/ChannelOpenProgressDialog.qml b/electrum/gui/qml/components/ChannelOpenProgressDialog.qml index 6179dd4c0..d251f7ee1 100644 --- a/electrum/gui/qml/components/ChannelOpenProgressDialog.qml +++ b/electrum/gui/qml/components/ChannelOpenProgressDialog.qml @@ -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 } } diff --git a/electrum/gui/qml/components/Channels.qml b/electrum/gui/qml/components/Channels.qml index 4369c8fbc..ea8c1283a 100644 --- a/electrum/gui/qml/components/Channels.qml +++ b/electrum/gui/qml/components/Channels.qml @@ -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 diff --git a/electrum/gui/qml/components/CloseChannelDialog.qml b/electrum/gui/qml/components/CloseChannelDialog.qml index cfae22c69..aafb51e82 100644 --- a/electrum/gui/qml/components/CloseChannelDialog.qml +++ b/electrum/gui/qml/components/CloseChannelDialog.qml @@ -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() + } } } } diff --git a/electrum/gui/qml/components/ConfirmTxDialog.qml b/electrum/gui/qml/components/ConfirmTxDialog.qml index f51a7f365..2faa088fa 100644 --- a/electrum/gui/qml/components/ConfirmTxDialog.qml +++ b/electrum/gui/qml/components/ConfirmTxDialog.qml @@ -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() + } } } diff --git a/electrum/gui/qml/components/Constants.qml b/electrum/gui/qml/components/Constants.qml index 95d79a479..ea08a2fac 100644 --- a/electrum/gui/qml/components/Constants.qml +++ b/electrum/gui/qml/components/Constants.qml @@ -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" diff --git a/electrum/gui/qml/components/CpfpBumpFeeDialog.qml b/electrum/gui/qml/components/CpfpBumpFeeDialog.qml index 1c8f7b127..69803bf50 100644 --- a/electrum/gui/qml/components/CpfpBumpFeeDialog.qml +++ b/electrum/gui/qml/components/CpfpBumpFeeDialog.qml @@ -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() + } } } } diff --git a/electrum/gui/qml/components/ExportTxDialog.qml b/electrum/gui/qml/components/ExportTxDialog.qml index 249f07c18..230c72dc7 100644 --- a/electrum/gui/qml/components/ExportTxDialog.qml +++ b/electrum/gui/qml/components/ExportTxDialog.qml @@ -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 diff --git a/electrum/gui/qml/components/GenericShareDialog.qml b/electrum/gui/qml/components/GenericShareDialog.qml index afaa75f62..b14730dc6 100644 --- a/electrum/gui/qml/components/GenericShareDialog.qml +++ b/electrum/gui/qml/components/GenericShareDialog.qml @@ -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 { diff --git a/electrum/gui/qml/components/History.qml b/electrum/gui/qml/components/History.qml index c99be7599..7b2782bb7 100644 --- a/electrum/gui/qml/components/History.qml +++ b/electrum/gui/qml/components/History.qml @@ -14,8 +14,8 @@ Pane { padding: 0 clip: true - background: Rectangle { - color: constants.darkerBackground + background: PaneInsetBackground { + vertical: false } ElListView { diff --git a/electrum/gui/qml/components/ImportAddressesKeysDialog.qml b/electrum/gui/qml/components/ImportAddressesKeysDialog.qml index e84d5e7e7..2f23cd6d7 100644 --- a/electrum/gui/qml/components/ImportAddressesKeysDialog.qml +++ b/electrum/gui/qml/components/ImportAddressesKeysDialog.qml @@ -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 diff --git a/electrum/gui/qml/components/ImportChannelBackupDialog.qml b/electrum/gui/qml/components/ImportChannelBackupDialog.qml deleted file mode 100644 index 4de22020e..000000000 --- a/electrum/gui/qml/components/ImportChannelBackupDialog.qml +++ /dev/null @@ -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() - } - } - -} diff --git a/electrum/gui/qml/components/InvoiceDialog.qml b/electrum/gui/qml/components/InvoiceDialog.qml index 51f41de5a..2a91e5888 100644 --- a/electrum/gui/qml/components/InvoiceDialog.qml +++ b/electrum/gui/qml/components/InvoiceDialog.qml @@ -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 { diff --git a/electrum/gui/qml/components/Invoices.qml b/electrum/gui/qml/components/Invoices.qml index e57223fd9..513449f0d 100644 --- a/electrum/gui/qml/components/Invoices.qml +++ b/electrum/gui/qml/components/Invoices.qml @@ -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 + } diff --git a/electrum/gui/qml/components/LnurlPayRequestDialog.qml b/electrum/gui/qml/components/LnurlPayRequestDialog.qml index 338dc08d8..da2a9f857 100644 --- a/electrum/gui/qml/components/LnurlPayRequestDialog.qml +++ b/electrum/gui/qml/components/LnurlPayRequestDialog.qml @@ -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() + } } } } diff --git a/electrum/gui/qml/components/LnurlWithdrawRequestDialog.qml b/electrum/gui/qml/components/LnurlWithdrawRequestDialog.qml index d5a84c6f1..e68c3843a 100644 --- a/electrum/gui/qml/components/LnurlWithdrawRequestDialog.qml +++ b/electrum/gui/qml/components/LnurlWithdrawRequestDialog.qml @@ -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(); + } } } } diff --git a/electrum/gui/qml/components/MessageDialog.qml b/electrum/gui/qml/components/MessageDialog.qml index a2211ff75..4452b3baa 100644 --- a/electrum/gui/qml/components/MessageDialog.qml +++ b/electrum/gui/qml/components/MessageDialog.qml @@ -46,8 +46,13 @@ ElDialog { } } - ButtonContainer { + DialogButtonContainer { Layout.fillWidth: true + function beforeLayout() { + if (!dialog.text) { + headerComponent = null + } + } FlatButton { Layout.fillWidth: true diff --git a/electrum/gui/qml/components/NetworkOverview.qml b/electrum/gui/qml/components/NetworkOverview.qml index 12ffdc65a..ffb893c1c 100644 --- a/electrum/gui/qml/components/NetworkOverview.qml +++ b/electrum/gui/qml/components/NetworkOverview.qml @@ -314,6 +314,7 @@ Pane { } } } + property color navigationBarBackgroundColor: constants.highlightBackground Component { id: serverConfig diff --git a/electrum/gui/qml/components/NostrConfigDialog.qml b/electrum/gui/qml/components/NostrConfigDialog.qml index f53646826..0eb6cfd86 100644 --- a/electrum/gui/qml/components/NostrConfigDialog.qml +++ b/electrum/gui/qml/components/NostrConfigDialog.qml @@ -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') + '

' + - 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() + } } } } diff --git a/electrum/gui/qml/components/OpenChannelDialog.qml b/electrum/gui/qml/components/OpenChannelDialog.qml index 97d709b52..a9b6f3d31 100644 --- a/electrum/gui/qml/components/OpenChannelDialog.qml +++ b/electrum/gui/qml/components/OpenChannelDialog.qml @@ -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 + } } diff --git a/electrum/gui/qml/components/OpenWalletDialog.qml b/electrum/gui/qml/components/OpenWalletDialog.qml index 51ec37e61..dbc5dad70 100644 --- a/electrum/gui/qml/components/OpenWalletDialog.qml +++ b/electrum/gui/qml/components/OpenWalletDialog.qml @@ -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 %1 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() { diff --git a/electrum/gui/qml/components/PasswordDialog.qml b/electrum/gui/qml/components/PasswordDialog.qml index 550f00b23..9f8c0bf19 100644 --- a/electrum/gui/qml/components/PasswordDialog.qml +++ b/electrum/gui/qml/components/PasswordDialog.qml @@ -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) + } } } } diff --git a/electrum/gui/qml/components/ProxyConfigDialog.qml b/electrum/gui/qml/components/ProxyConfigDialog.qml index c3d6bf31b..fb31db19f 100644 --- a/electrum/gui/qml/components/ProxyConfigDialog.qml +++ b/electrum/gui/qml/components/ProxyConfigDialog.qml @@ -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() + } } } } diff --git a/electrum/gui/qml/components/RbfBumpFeeDialog.qml b/electrum/gui/qml/components/RbfBumpFeeDialog.qml index 4d9fdcf9c..f3e5fcdf6 100644 --- a/electrum/gui/qml/components/RbfBumpFeeDialog.qml +++ b/electrum/gui/qml/components/RbfBumpFeeDialog.qml @@ -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() + } } } } diff --git a/electrum/gui/qml/components/RbfCancelDialog.qml b/electrum/gui/qml/components/RbfCancelDialog.qml index b8832b10d..5e9b5d7b6 100644 --- a/electrum/gui/qml/components/RbfCancelDialog.qml +++ b/electrum/gui/qml/components/RbfCancelDialog.qml @@ -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() + } } } } diff --git a/electrum/gui/qml/components/ReceiveDetailsDialog.qml b/electrum/gui/qml/components/ReceiveDetailsDialog.qml index c29df76b9..964bdd2d0 100644 --- a/electrum/gui/qml/components/ReceiveDetailsDialog.qml +++ b/electrum/gui/qml/components/ReceiveDetailsDialog.qml @@ -95,7 +95,7 @@ ElDialog { } } - ButtonContainer { + DialogButtonContainer { Layout.fillWidth: true FlatButton { diff --git a/electrum/gui/qml/components/ReceiveDialog.qml b/electrum/gui/qml/components/ReceiveDialog.qml index 19982d05f..b7ebf3cc9 100644 --- a/electrum/gui/qml/components/ReceiveDialog.qml +++ b/electrum/gui/qml/components/ReceiveDialog.qml @@ -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 diff --git a/electrum/gui/qml/components/ReceiveRequests.qml b/electrum/gui/qml/components/ReceiveRequests.qml index c6792fdd1..e389a48b1 100644 --- a/electrum/gui/qml/components/ReceiveRequests.qml +++ b/electrum/gui/qml/components/ReceiveRequests.qml @@ -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 } diff --git a/electrum/gui/qml/components/ScanDialog.qml b/electrum/gui/qml/components/ScanDialog.qml index d8e4ed93a..8b6b3d750 100644 --- a/electrum/gui/qml/components/ScanDialog.qml +++ b/electrum/gui/qml/components/ScanDialog.qml @@ -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() } diff --git a/electrum/gui/qml/components/SendDialog.qml b/electrum/gui/qml/components/SendDialog.qml index e17c45ce4..6244823f8 100644 --- a/electrum/gui/qml/components/SendDialog.qml +++ b/electrum/gui/qml/components/SendDialog.qml @@ -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 { diff --git a/electrum/gui/qml/components/ServerConfigDialog.qml b/electrum/gui/qml/components/ServerConfigDialog.qml index 9fed62953..688cf0f54 100644 --- a/electrum/gui/qml/components/ServerConfigDialog.qml +++ b/electrum/gui/qml/components/ServerConfigDialog.qml @@ -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() + } } } } diff --git a/electrum/gui/qml/components/SignVerifyMessageDialog.qml b/electrum/gui/qml/components/SignVerifyMessageDialog.qml index 4a6321bac..a37ce2c78 100644 --- a/electrum/gui/qml/components/SignVerifyMessageDialog.qml +++ b/electrum/gui/qml/components/SignVerifyMessageDialog.qml @@ -179,8 +179,9 @@ ElDialog { } } - ButtonContainer { + DialogButtonContainer { Layout.fillWidth: true + FlatButton { Layout.fillWidth: true Layout.preferredWidth: 1 diff --git a/electrum/gui/qml/components/SwapDialog.qml b/electrum/gui/qml/components/SwapDialog.qml index 126b602b0..d3eead881 100644 --- a/electrum/gui/qml/components/SwapDialog.qml +++ b/electrum/gui/qml/components/SwapDialog.qml @@ -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 { diff --git a/electrum/gui/qml/components/SweepDialog.qml b/electrum/gui/qml/components/SweepDialog.qml index 849a70356..a23ff6723 100644 --- a/electrum/gui/qml/components/SweepDialog.qml +++ b/electrum/gui/qml/components/SweepDialog.qml @@ -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 { diff --git a/electrum/gui/qml/components/TxDetails.qml b/electrum/gui/qml/components/TxDetails.qml index 42f462a2e..0a5d217be 100644 --- a/electrum/gui/qml/components/TxDetails.qml +++ b/electrum/gui/qml/components/TxDetails.qml @@ -480,6 +480,7 @@ Pane { } } + property color navigationBarBackgroundColor: constants.highlightBackground TxDetails { id: txdetails diff --git a/electrum/gui/qml/components/WalletDetails.qml b/electrum/gui/qml/components/WalletDetails.qml index 9db036f9a..4456c80e8 100644 --- a/electrum/gui/qml/components/WalletDetails.qml +++ b/electrum/gui/qml/components/WalletDetails.qml @@ -517,6 +517,7 @@ Pane { } } } + property color navigationBarBackgroundColor: constants.highlightBackground Connections { target: Daemon diff --git a/electrum/gui/qml/components/WalletMainView.qml b/electrum/gui/qml/components/WalletMainView.qml index c39cda5ed..55f73519d 100644 --- a/electrum/gui/qml/components/WalletMainView.qml +++ b/electrum/gui/qml/components/WalletMainView.qml @@ -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 diff --git a/electrum/gui/qml/components/WalletSummary.qml b/electrum/gui/qml/components/WalletSummary.qml deleted file mode 100644 index baddd0645..000000000 --- a/electrum/gui/qml/components/WalletSummary.qml +++ /dev/null @@ -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() - } - } - -} diff --git a/electrum/gui/qml/components/Wallets.qml b/electrum/gui/qml/components/Wallets.qml index b38fdf78a..e98e82c14 100644 --- a/electrum/gui/qml/components/Wallets.qml +++ b/electrum/gui/qml/components/Wallets.qml @@ -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 diff --git a/electrum/gui/qml/components/controls/BtcField.qml b/electrum/gui/qml/components/controls/BtcField.qml index a42624356..ce11cfe1f 100644 --- a/electrum/gui/qml/components/controls/BtcField.qml +++ b/electrum/gui/qml/components/controls/BtcField.qml @@ -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) diff --git a/electrum/gui/qml/components/controls/ButtonContainer.qml b/electrum/gui/qml/components/controls/ButtonContainer.qml index 527897c0b..59cc6fe3a 100644 --- a/electrum/gui/qml/components/controls/ButtonContainer.qml +++ b/electrum/gui/qml/components/controls/ButtonContainer.qml @@ -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 { } } + diff --git a/electrum/gui/qml/components/controls/ChannelBar.qml b/electrum/gui/qml/components/controls/ChannelBar.qml index 8635356f7..4f67dd765 100644 --- a/electrum/gui/qml/components/controls/ChannelBar.qml +++ b/electrum/gui/qml/components/controls/ChannelBar.qml @@ -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 diff --git a/electrum/gui/qml/components/controls/DialogButtonContainer.qml b/electrum/gui/qml/components/controls/DialogButtonContainer.qml new file mode 100644 index 000000000..3c7f9f1ba --- /dev/null +++ b/electrum/gui/qml/components/controls/DialogButtonContainer.qml @@ -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 + } + } +} diff --git a/electrum/gui/qml/components/controls/DialogHighlightPane.qml b/electrum/gui/qml/components/controls/DialogHighlightPane.qml new file mode 100644 index 000000000..1913972ec --- /dev/null +++ b/electrum/gui/qml/components/controls/DialogHighlightPane.qml @@ -0,0 +1,5 @@ +import QtQuick + +TextHighlightPane { + backgroundColor: constants.darkerDialogBackground +} diff --git a/electrum/gui/qml/components/controls/ElDialog.qml b/electrum/gui/qml/components/controls/ElDialog.qml index 74bd44c21..b90402c9e 100644 --- a/electrum/gui/qml/components/controls/ElDialog.qml +++ b/electrum/gui/qml/components/controls/ElDialog.qml @@ -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 } } diff --git a/electrum/gui/qml/components/controls/FlatButton.qml b/electrum/gui/qml/components/controls/FlatButton.qml index 621dec49b..ab3f0e409 100644 --- a/electrum/gui/qml/components/controls/FlatButton.qml +++ b/electrum/gui/qml/components/controls/FlatButton.qml @@ -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 + } + } + } + } + } } diff --git a/electrum/gui/qml/components/controls/FormattedAmount.qml b/electrum/gui/qml/components/controls/FormattedAmount.qml index 80d6d778a..43c57e68c 100644 --- a/electrum/gui/qml/components/controls/FormattedAmount.qml +++ b/electrum/gui/qml/components/controls/FormattedAmount.qml @@ -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 diff --git a/electrum/gui/qml/components/controls/HelpDialog.qml b/electrum/gui/qml/components/controls/HelpDialog.qml index ac7dac0ad..28724b538 100644 --- a/electrum/gui/qml/components/controls/HelpDialog.qml +++ b/electrum/gui/qml/components/controls/HelpDialog.qml @@ -35,7 +35,7 @@ ElDialog { implicitHeight: rootLayout.height + topPadding + bottomPadding padding: constants.paddingLarge background: Rectangle { - color: constants.lighterBackground + color: constants.highlightBackground } ColumnLayout { id: rootLayout diff --git a/electrum/gui/qml/components/controls/PaneInsetBackground.qml b/electrum/gui/qml/components/controls/PaneInsetBackground.qml index 9762e4101..8733a5705 100644 --- a/electrum/gui/qml/components/controls/PaneInsetBackground.qml +++ b/electrum/gui/qml/components/controls/PaneInsetBackground.qml @@ -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) } diff --git a/electrum/gui/qml/components/controls/PasswordField.qml b/electrum/gui/qml/components/controls/PasswordField.qml index e9fc0e10d..064ed6480 100644 --- a/electrum/gui/qml/components/controls/PasswordField.qml +++ b/electrum/gui/qml/components/controls/PasswordField.qml @@ -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 diff --git a/electrum/gui/qml/components/controls/ProxyConfig.qml b/electrum/gui/qml/components/controls/ProxyConfig.qml index 05bc05b2b..e1e665d6e 100644 --- a/electrum/gui/qml/components/controls/ProxyConfig.qml +++ b/electrum/gui/qml/components/controls/ProxyConfig.qml @@ -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() } } diff --git a/electrum/gui/qml/components/controls/SeedKeyboardKey.qml b/electrum/gui/qml/components/controls/SeedKeyboardKey.qml index fa5fcc9f9..68b08c3d5 100644 --- a/electrum/gui/qml/components/controls/SeedKeyboardKey.qml +++ b/electrum/gui/qml/components/controls/SeedKeyboardKey.qml @@ -19,6 +19,10 @@ Pane { kbd.keyEvent(keycode, key) } + background: Rectangle { + color: constants.darkerDialogBackground + } + FlatButton { anchors.fill: parent diff --git a/electrum/gui/qml/components/controls/SeedTextArea.qml b/electrum/gui/qml/components/controls/SeedTextArea.qml index 76952ccad..9674c008f 100644 --- a/electrum/gui/qml/components/controls/SeedTextArea.qml +++ b/electrum/gui/qml/components/controls/SeedTextArea.qml @@ -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) diff --git a/electrum/gui/qml/components/controls/ServerConfig.qml b/electrum/gui/qml/components/controls/ServerConfig.qml index aae493bae..0df5cb786 100644 --- a/electrum/gui/qml/components/controls/ServerConfig.qml +++ b/electrum/gui/qml/components/controls/ServerConfig.qml @@ -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') + '

' + Config.getTranslatedMessage('MSG_CONNECTMODE_NODES_HELP') + '