Merge branch 'staging' into wow

# Conflicts:
#	assets/images/wownero.png
#	lib/pages/add_wallet_views/restore_wallet_view/restore_wallet_view.dart
#	lib/services/coins/coin_service.dart
#	lib/utilities/address_utils.dart
#	lib/utilities/assets.dart
#	lib/utilities/cfcolors.dart
#	lib/utilities/constants.dart
#	lib/utilities/default_nodes.dart
#	lib/utilities/enums/coin_enum.dart
#	pubspec.yaml
This commit is contained in:
Marco 2022-09-27 16:16:20 +08:00
commit 26b7306d22
301 changed files with 27634 additions and 4941 deletions

3
.gitignore vendored
View file

@ -37,6 +37,8 @@ lib/generated_plugin_registrant.dart
test/services/coins/bitcoin/bitcoin_wallet_test_parameters.dart test/services/coins/bitcoin/bitcoin_wallet_test_parameters.dart
test/services/coins/firo/firo_wallet_test_parameters.dart test/services/coins/firo/firo_wallet_test_parameters.dart
test/services/coins/dogecoin/dogecoin_wallet_test_parameters.dart test/services/coins/dogecoin/dogecoin_wallet_test_parameters.dart
test/services/coins/namecoin/namecoin_wallet_test_parameters.dart
test/services/coins/bitcoincash/bitcoincash_wallet_test_parameters.dart
/integration_test/private.dart /integration_test/private.dart
# Exceptions to above rules. # Exceptions to above rules.
@ -46,3 +48,4 @@ test/services/coins/dogecoin/dogecoin_wallet_test_parameters.dart
coverage coverage
scripts/**/build scripts/**/build
/lib/external_api_keys.dart /lib/external_api_keys.dart
/test/services/coins/bitcoincash/bitcoincash_wallet_test_parameters.dart

Binary file not shown.

After

Width:  |  Height:  |  Size: 354 KiB

BIN
assets/images/namecoin.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 351 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 284 KiB

After

Width:  |  Height:  |  Size: 371 KiB

View file

@ -0,0 +1,4 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M11.25 12C12.907 12 14.25 10.657 14.25 9C14.25 7.34297 12.907 6 11.25 6C9.59344 6 8.25 7.34297 8.25 9C8.25 10.657 9.59531 12 11.25 12ZM12.75 13.5H9.75C7.67812 13.5 6 15.1781 6 17.25C6 17.6625 6.3375 18 6.75 18H15.75C16.1642 18 16.5 17.6642 16.5 17.25C16.5 15.1781 14.8219 13.5 12.75 13.5ZM23.25 3H21V7.5H23.25C23.6625 7.5 24 7.1625 24 6.75V3.75C24 3.33562 23.6625 3 23.25 3ZM23.25 15H21V19.5H23.25C23.6642 19.5 24 19.1642 24 18.75V15.75C24 15.3375 23.6625 15 23.25 15ZM23.25 9H21V13.5H23.25C23.6625 13.5 24 13.1625 24 12.75V9.75C24 9.3375 23.6625 9 23.25 9Z" fill="#232323"/>
<path opacity="0.4" d="M18.75 0H3.75C2.50734 0 1.5 1.00734 1.5 2.25V21.75C1.5 22.9922 2.50734 24 3.75 24H18.75C19.9927 24 21 22.9927 21 21.75V2.25C21 1.00734 19.9922 0 18.75 0ZM11.25 6C12.907 6 14.25 7.34297 14.25 9C14.25 10.657 12.907 12 11.25 12C9.59344 12 8.25 10.657 8.25 9C8.25 7.34297 9.59531 6 11.25 6ZM15.75 18H6.75C6.3375 18 6 17.6625 6 17.25C6 15.1781 7.67812 13.5 9.75 13.5H12.75C14.8209 13.5 16.5 15.1791 16.5 17.25C16.5 17.6625 16.1625 18 15.75 18Z" fill="#232323"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View file

@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M9 18L15 12L9 6" stroke="#8E9192" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 212 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 511.76 511.76"><title>bitcoin-cash-bch</title><circle style="fill:#0ac18e;" cx="255.88" cy="255.88" r="255.88"/><path id="symbol" style="fill:#fff;" d="M335.94,170.3c-12.86-29.16-42.41-35.4-78.59-29.36L245.73,95.87,218.32,103l11.43,44.94c-7.21,1.82-14.61,3.38-21.95,5.46l-11.43-44.68L169,115.75l11.63,45.07c-5.91,1.69-55.33,14.35-55.33,14.35l7.53,29.35s20.13-5.65,19.94-5.19c11.17-2.92,16.43,2.66,18.9,7.92l32,123.53c.39,3.57-.26,9.67-7.92,11.75.45.26-19.94,5.13-19.94,5.13l3,34.23s49-12.54,55.4-14.16l11.76,45.59,27.4-7.08-11.75-45.91q11.3-2.64,22-5.46l11.69,45.66,27.4-7.08-11.75-45.53c42.21-10.26,72-36.89,65.92-77.61-3.9-24.55-30.72-44.68-53-46.95,13.7-12.15,20.65-29.88,12.15-53.06ZM322.75,277.78c5.46,40.33-50.59,45.27-69.1,50.14l-16.11-60.33C256.12,262.71,313.53,242.26,322.75,277.78ZM289,195.63c5.78,35.85-42.15,40-57.61,44L216.7,184.85C232.22,181,277.23,162.44,289,195.63Z" transform="translate(-0.24 -0.34)"/></svg>

After

Width:  |  Height:  |  Size: 978 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32"><g fill="none" fill-rule="evenodd"><circle cx="16" cy="16" r="16" fill="#186C9D"/><path fill="#FFF" fill-rule="nonzero" d="M19.261 23.5l.001-.002a1.8 1.8 0 0 0 .458-.05c.876-.205 1.617-.97 1.793-1.796L25 8.556l-2.772-.014-2.286 8.568-6.18-8.597-.004.004.003-.01L12.74 8.5v.001a1.9 1.9 0 0 0-.459.049c-.875.206-1.616.971-1.793 1.796L7 23.445l2.773.012 2.285-8.568 6.18 8.598h.003l1.02.013zm-6.593-10.894l.483-1.81 6.181 8.599-.483 1.81-6.18-8.6z"/></g></svg>

After

Width:  |  Height:  |  Size: 520 B

View file

@ -0,0 +1,5 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M15 21C15 21.5031 14.6859 22.0406 14.1234 22.4156C13.5609 22.7906 12.7547 23 12 23C11.2031 23 10.4391 22.7906 9.87656 22.4156C9.31406 22.0406 9 21.5031 9 21H15Z" fill="#E0E3E3"/>
<path d="M13.4279 2.38462V3.21538C16.6867 3.85707 19.1419 6.65096 19.1419 10V10.8135C19.1419 12.8514 19.9142 14.8115 21.307 16.3346L21.6373 16.6938C22.0123 17.1048 22.106 17.6846 21.8739 18.1822C21.6418 18.6798 21.1329 19 20.5704 19H3.42848C2.86601 19 2.35582 18.6798 2.12538 18.1822C1.89495 17.6846 1.98712 17.1048 2.36086 16.6938L2.69192 16.3346C4.08648 14.8115 4.85697 12.8514 4.85697 10.8135V10C4.85697 6.65096 7.27202 3.85707 10.5709 3.21538V2.38462C10.5709 1.62005 11.2093 1 11.9994 1C12.7896 1 13.4279 1.62005 13.4279 2.38462Z" fill="#E0E3E3"/>
<circle cx="20.5" cy="3.5" r="2.5" fill="#C00205"/>
</svg>

After

Width:  |  Height:  |  Size: 895 B

View file

@ -0,0 +1,18 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_5101_18544)">
<g opacity="0.4">
<path d="M22.2 6C23.3297 5.37187 24 4.59422 24 3.75C24 1.67906 19.9688 0 15 0C9.98906 0 6 1.67906 6 3.75C6 4.59422 6.67031 5.37187 7.8 6C7.80937 6.00469 7.81758 6.00937 7.82578 6.01406C7.83398 6.01875 7.84219 6.02344 7.85156 6.02813C8.23125 6.00938 8.61094 6 9 6C11.6344 6 14.0906 6.44062 15.9422 7.21406C16.1203 7.28906 16.2984 7.36875 16.4672 7.44844C18.8062 7.28906 20.8359 6.75469 22.2 6Z" fill="white"/>
<path d="M19.9435 12.9151C19.7958 12.9551 19.6477 12.9951 19.5 13.0359V13.5C20.7602 13.5 21.9296 13.8885 22.8951 14.5522C23.5995 14.0172 24 13.4028 24 12.75V11.0906C23.4141 11.5734 22.7063 11.9672 21.9422 12.2859C21.3382 12.5376 20.6447 12.7253 19.9435 12.9151Z" fill="white"/>
<path d="M18.3703 8.74688C19.0031 9.37969 19.5 10.2234 19.5 11.25V11.4984C20.4328 11.2734 21.2625 10.9781 21.9469 10.6359C21.9739 10.6209 22.0009 10.6021 22.0279 10.5833C22.0852 10.5432 22.1426 10.5032 22.2 10.5C23.3297 9.87187 24 9.09375 24 8.25V6.59063C23.4141 7.07344 22.7063 7.46719 21.9422 7.78594C20.9109 8.2125 19.6969 8.54063 18.3703 8.74688Z" fill="white"/>
</g>
<path d="M16.2 13.5C17.3297 12.8719 18 12.0938 18 11.25C18 9.17813 13.9688 7.5 9 7.5C4.02938 7.5 0 9.17813 0 11.25C0 12.0938 0.669375 12.8719 1.79953 13.5C1.85443 13.5031 1.91057 13.5415 1.96782 13.5807C1.9966 13.6004 2.02567 13.6203 2.055 13.6359C3.70594 14.4703 6.20625 15 9 15C11.9438 15 14.5594 14.4094 16.2 13.5Z" fill="white"/>
<path d="M14.8788 15.6729C13.1948 16.2046 11.1571 16.5 9 16.5C6.36562 16.5 3.91125 16.0594 2.05922 15.2859C1.29469 14.9672 0.583594 14.5734 0 14.0906V15.75C0 16.5938 0.669375 17.3719 1.79953 18C3.44109 18.9094 6.05625 19.5 9 19.5C10.6471 19.5 12.1916 19.3159 13.5211 18.9937C13.6261 17.7367 14.1186 16.5898 14.8788 15.6729Z" fill="white"/>
<path d="M13.5862 20.5191C13.7529 21.4936 14.1547 22.3879 14.731 23.1415C13.1742 23.6778 11.1771 24 9 24C4.02938 24 0 22.3219 0 20.25V18.5906C0.583594 19.0734 1.29469 19.4672 2.05922 19.7859C3.91125 20.5594 6.36562 21 9 21C10.6307 21 12.1932 20.8312 13.5862 20.5191Z" fill="white"/>
<path d="M24 19.5C24 21.9844 21.9844 24 19.5 24C17.0156 24 15 21.9844 15 19.5C15 17.0156 17.0156 15 19.5 15C21.9844 15 24 17.0156 24 19.5ZM19 17.4719V18.9719H17.5C17.225 18.9719 17 19.225 17 19.4719C17 19.775 17.225 19.9719 17.5 19.9719H19V21.4719C19 21.775 19.225 21.9719 19.5 21.9719C19.775 21.9719 20 21.775 20 21.4719V19.9719H21.5C21.775 19.9719 22 19.775 22 19.4719C22 19.225 21.775 18.9719 21.5 18.9719H20V17.4719C20 17.225 19.775 16.9719 19.5 16.9719C19.225 16.9719 19 17.225 19 17.4719Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0_5101_18544">
<rect width="24" height="24" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

View file

@ -0,0 +1,11 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_5101_7226)">
<path d="M19.5 6.5L20.4343 7.33045C20.8552 6.85685 20.8552 6.14315 20.4343 5.66955L19.5 6.5ZM16.4343 1.16955C15.9756 0.653567 15.1855 0.607091 14.6695 1.06574C14.1536 1.52439 14.1071 2.31448 14.5657 2.83045L16.4343 1.16955ZM14.5657 10.1695C14.1071 10.6855 14.1536 11.4756 14.6695 11.9343C15.1855 12.3929 15.9756 12.3464 16.4343 11.8305L14.5657 10.1695ZM0.75 10.5C0.75 11.1904 1.30964 11.75 2 11.75C2.69036 11.75 3.25 11.1904 3.25 10.5H0.75ZM6 7.75H19.5V5.25H6V7.75ZM14.5657 2.83045L18.5657 7.33045L20.4343 5.66955L16.4343 1.16955L14.5657 2.83045ZM16.4343 11.8305L20.4343 7.33045L18.5657 5.66955L14.5657 10.1695L16.4343 11.8305ZM3.25 10.5C3.25 8.98122 4.48122 7.75 6 7.75V5.25C3.10051 5.25 0.75 7.60051 0.75 10.5H3.25Z" fill="white"/>
<path opacity="0.4" d="M4.5 18L3.56574 17.1695C3.14475 17.6432 3.14475 18.3568 3.56574 18.8305L4.5 18ZM7.56574 23.3305C8.02439 23.8464 8.81448 23.8929 9.33045 23.4343C9.84643 22.9756 9.89291 22.1855 9.43426 21.6695L7.56574 23.3305ZM9.43426 14.3305C9.89291 13.8145 9.84643 13.0244 9.33046 12.5657C8.81448 12.1071 8.02439 12.1536 7.56574 12.6695L9.43426 14.3305ZM23.25 14C23.25 13.3096 22.6904 12.75 22 12.75C21.3096 12.75 20.75 13.3096 20.75 14L23.25 14ZM18 16.75L4.5 16.75L4.5 19.25L18 19.25L18 16.75ZM9.43426 21.6695L5.43426 17.1695L3.56574 18.8305L7.56574 23.3305L9.43426 21.6695ZM7.56574 12.6695L3.56574 17.1695L5.43426 18.8305L9.43426 14.3305L7.56574 12.6695ZM20.75 14C20.75 15.5188 19.5188 16.75 18 16.75L18 19.25C20.8995 19.25 23.25 16.8995 23.25 14L20.75 14Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0_5101_7226">
<rect width="24" height="24" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View file

@ -0,0 +1,5 @@
<svg width="60" height="47" viewBox="0 0 60 47" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M35.4652 0.708774C31.9724 -1.30683 27.6074 1.21691 27.6074 5.24811C27.6074 9.27931 29.5549 12.7727 32.7471 14.9281L46.2653 22.7661L46.2992 22.7534L59.9995 14.8349L35.4652 0.708774Z" fill="white"/>
<path d="M32.7438 14.9285C29.5515 12.7731 27.604 9.14421 27.604 5.24851C27.604 3.3303 28.6074 1.72968 30.0342 0.823501C29.9664 0.861612 30.1019 0.785391 30.0342 0.823501L8.64977 12.8409L5.21624 14.9158L2.875 16.2623C4.34833 15.5128 6.19422 15.4535 7.84113 16.4105L13.7302 19.7642L18.8911 22.7495L32.5913 30.6552L46.2577 22.758L32.7395 14.92L32.7438 14.9285Z" fill="#999999"/>
<path d="M60 30.6636L32.5953 46.5005L27.4217 43.5152L27.4005 43.494L5.19475 30.6636C3.67485 29.6728 2.43861 28.322 1.56647 26.8018C0.550381 25.0487 0 23.0331 0 20.9455C0 19.0654 0.944115 17.5114 2.31583 16.5883C2.50212 16.4739 2.68417 16.3681 2.87892 16.2665C4.35224 15.517 6.19814 15.4577 7.84505 16.4147L13.7003 19.7938L18.8611 22.7664L18.895 22.7536L32.5953 30.6594L46.2616 22.7621L60 30.6594V30.6636Z" fill="#4C4C4C"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View file

@ -0,0 +1,14 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_5094_29952)">
<path d="M23.0154 16.7681C23.6489 15.3066 24 13.6943 24 12C24 5.37258 18.6274 0 12 0C5.37258 0 0 5.37258 0 12C0 18.6274 5.37258 24 12 24C13.6943 24 15.3066 23.6489 16.7681 23.0154C16.2832 22.2973 16 21.4317 16 20.5C16 18.0147 18.0147 16 20.5 16C21.4317 16 22.2973 16.2832 23.0154 16.7681Z" fill="#B4C4FF"/>
<path d="M5.30071 12.4C4.91018 12.7905 4.91018 13.4236 5.30071 13.8142C5.69123 14.2047 6.32439 14.2047 6.71492 13.8142L5.30071 12.4ZM13.0789 6.03599L14.0787 6.05567C14.0839 5.78863 13.9821 5.53058 13.796 5.33904C13.6098 5.1475 13.3548 5.03839 13.0877 5.03603L13.0789 6.03599ZM9.00968 5.00004C8.45741 4.99516 8.00576 5.43891 8.00089 5.99117C7.99601 6.54344 8.43976 6.99509 8.99202 6.99996L9.00968 5.00004ZM12.001 9.98032C11.9902 10.5325 12.429 10.9889 12.9812 10.9998C13.5333 11.0107 13.9898 10.5719 14.0007 10.0197L12.001 9.98032ZM18.6429 11.6C19.0334 11.2095 19.0334 10.5764 18.6429 10.1858C18.2524 9.79531 17.6192 9.79531 17.2287 10.1858L18.6429 11.6ZM10.8647 17.964L9.8653 17.9297C9.85604 18.1992 9.95602 18.461 10.1426 18.6557C10.3291 18.8505 10.5864 18.9616 10.856 18.964L10.8647 17.964ZM14.9922 19C15.5444 19.0048 15.996 18.561 16.0008 18.0087C16.0056 17.4564 15.5618 17.0048 15.0096 17L14.9922 19ZM12.0003 14.0343C12.0192 13.4824 11.5871 13.0195 11.0352 13.0006C10.4832 12.9816 10.0204 13.4137 10.0014 13.9657L12.0003 14.0343ZM6.71492 13.8142L13.786 6.7431L12.3718 5.32889L5.30071 12.4L6.71492 13.8142ZM8.99202 6.99996L13.0701 7.03595L13.0877 5.03603L9.00968 5.00004L8.99202 6.99996ZM12.0791 6.01631L12.001 9.98032L14.0007 10.0197L14.0787 6.05567L12.0791 6.01631ZM17.2287 10.1858L10.1576 17.2569L11.5718 18.6711L18.6429 11.6L17.2287 10.1858ZM15.0096 17L10.8734 16.964L10.856 18.964L14.9922 19L15.0096 17ZM11.8641 17.9983L12.0003 14.0343L10.0014 13.9657L9.8653 17.9297L11.8641 17.9983Z" fill="#00297A"/>
<circle cx="20.5" cy="20.5" r="3.5" fill="#D34E50"/>
<path d="M19.4395 19.4395L20.5001 20.5001L21.5608 21.5608" stroke="#2A2D34" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M19.5 21.5605L20.5607 20.4999L21.6213 19.4392" stroke="#2A2D34" stroke-linecap="round" stroke-linejoin="round"/>
</g>
<defs>
<clipPath id="clip0_5094_29952">
<rect width="24" height="24" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

View file

@ -0,0 +1,13 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_5094_29944)">
<path d="M23.0154 16.7681C23.6489 15.3066 24 13.6943 24 12C24 5.37258 18.6274 0 12 0C5.37258 0 0 5.37258 0 12C0 18.6274 5.37258 24 12 24C13.6943 24 15.3066 23.6489 16.7681 23.0154C16.2832 22.2973 16 21.4317 16 20.5C16 18.0147 18.0147 16 20.5 16C21.4317 16 22.2973 16.2832 23.0154 16.7681Z" fill="#B4C4FF"/>
<circle cx="20.5" cy="20.5" r="3.5" fill="#F7D65D"/>
<path d="M20.5 19V20.5H21.5" stroke="#2A2D34" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M5.30071 12.4C4.91018 12.7905 4.91018 13.4236 5.30071 13.8142C5.69123 14.2047 6.32439 14.2047 6.71492 13.8142L5.30071 12.4ZM13.0789 6.03599L14.0787 6.05567C14.0839 5.78863 13.9821 5.53058 13.796 5.33904C13.6098 5.1475 13.3548 5.03839 13.0877 5.03603L13.0789 6.03599ZM9.00968 5.00004C8.45741 4.99516 8.00576 5.43891 8.00089 5.99117C7.99601 6.54344 8.43976 6.99509 8.99202 6.99996L9.00968 5.00004ZM12.001 9.98032C11.9902 10.5325 12.429 10.9889 12.9812 10.9998C13.5333 11.0107 13.9898 10.5719 14.0007 10.0197L12.001 9.98032ZM18.6429 11.6C19.0334 11.2095 19.0334 10.5764 18.6429 10.1858C18.2524 9.79531 17.6192 9.79531 17.2287 10.1858L18.6429 11.6ZM10.8647 17.964L9.8653 17.9297C9.85605 18.1992 9.95602 18.461 10.1426 18.6557C10.3291 18.8505 10.5864 18.9616 10.856 18.964L10.8647 17.964ZM14.9922 19C15.5444 19.0048 15.996 18.561 16.0008 18.0087C16.0056 17.4564 15.5618 17.0048 15.0096 17L14.9922 19ZM12.0003 14.0343C12.0192 13.4824 11.5871 13.0195 11.0352 13.0006C10.4832 12.9816 10.0204 13.4137 10.0014 13.9657L12.0003 14.0343ZM6.71492 13.8142L13.786 6.7431L12.3718 5.32889L5.30071 12.4L6.71492 13.8142ZM8.99202 6.99996L13.0701 7.03595L13.0877 5.03603L9.00968 5.00004L8.99202 6.99996ZM12.0791 6.01631L12.001 9.98032L14.0007 10.0197L14.0787 6.05567L12.0791 6.01631ZM17.2287 10.1858L10.1576 17.2569L11.5718 18.6711L18.6429 11.6L17.2287 10.1858ZM15.0096 17L10.8734 16.964L10.856 18.964L14.9922 19L15.0096 17ZM11.8641 17.9983L12.0003 14.0343L10.0014 13.9657L9.8653 17.9297L11.8641 17.9983Z" fill="#00297A"/>
</g>
<defs>
<clipPath id="clip0_5094_29944">
<rect width="24" height="24" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View file

@ -0,0 +1,11 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_5094_29949)">
<circle cx="12" cy="12" r="12" fill="#B4C4FF"/>
<path d="M5.30071 12.4C4.91018 12.7905 4.91018 13.4236 5.30071 13.8142C5.69123 14.2047 6.32439 14.2047 6.71492 13.8142L5.30071 12.4ZM13.0789 6.03599L14.0787 6.05567C14.0839 5.78863 13.9821 5.53058 13.796 5.33904C13.6098 5.1475 13.3548 5.03839 13.0877 5.03603L13.0789 6.03599ZM9.00968 5.00004C8.45741 4.99516 8.00576 5.43891 8.00089 5.99117C7.99601 6.54344 8.43976 6.99509 8.99202 6.99996L9.00968 5.00004ZM12.001 9.98032C11.9902 10.5325 12.429 10.9889 12.9812 10.9998C13.5333 11.0107 13.9898 10.5719 14.0007 10.0197L12.001 9.98032ZM18.6429 11.6C19.0334 11.2095 19.0334 10.5764 18.6429 10.1858C18.2524 9.79531 17.6192 9.79531 17.2287 10.1858L18.6429 11.6ZM10.8647 17.964L9.8653 17.9297C9.85604 18.1992 9.95602 18.461 10.1426 18.6557C10.3291 18.8505 10.5864 18.9616 10.856 18.964L10.8647 17.964ZM14.9922 19C15.5444 19.0048 15.996 18.561 16.0008 18.0087C16.0056 17.4564 15.5618 17.0048 15.0096 17L14.9922 19ZM12.0003 14.0343C12.0192 13.4824 11.5871 13.0195 11.0352 13.0006C10.4832 12.9816 10.0204 13.4137 10.0014 13.9657L12.0003 14.0343ZM6.71492 13.8142L13.786 6.7431L12.3718 5.32889L5.30071 12.4L6.71492 13.8142ZM8.99202 6.99996L13.0701 7.03595L13.0877 5.03603L9.00968 5.00004L8.99202 6.99996ZM12.0791 6.01631L12.001 9.98032L14.0007 10.0197L14.0787 6.05567L12.0791 6.01631ZM17.2287 10.1858L10.1576 17.2569L11.5718 18.6711L18.6429 11.6L17.2287 10.1858ZM15.0096 17L10.8734 16.964L10.856 18.964L14.9922 19L15.0096 17ZM11.8641 17.9983L12.0003 14.0343L10.0014 13.9657L9.8653 17.9297L11.8641 17.9983Z" fill="#00297A"/>
</g>
<defs>
<clipPath id="clip0_5094_29949">
<rect width="24" height="24" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

View file

@ -0,0 +1,14 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_5094_29925)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M23.0154 16.7681C23.6489 15.3066 24 13.6943 24 12C24 5.37258 18.6274 0 12 0C5.37258 0 0 5.37258 0 12C0 18.6274 5.37258 24 12 24C13.6943 24 15.3066 23.6489 16.7681 23.0154C16.2832 22.2973 16 21.4317 16 20.5C16 18.0147 18.0147 16 20.5 16C21.4317 16 22.2973 16.2832 23.0154 16.7681Z" fill="#8EF5C3"/>
<circle cx="20.5" cy="20.5" r="3.5" fill="#D34E50"/>
<path d="M16 8L8 16M8 16H14M8 16V10" stroke="#003921" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M19.4395 19.4395L20.5001 20.5001L21.5608 21.5608" stroke="#2A2D34" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M19.5 21.5605L20.5607 20.4999L21.6213 19.4392" stroke="#2A2D34" stroke-linecap="round" stroke-linejoin="round"/>
</g>
<defs>
<clipPath id="clip0_5094_29925">
<rect width="24" height="24" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1,020 B

View file

@ -0,0 +1,12 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_5094_29921)">
<path d="M23.0154 16.7681C23.6489 15.3066 24 13.6943 24 12C24 5.37258 18.6274 0 12 0C5.37258 0 0 5.37258 0 12C0 18.6274 5.37258 24 12 24C13.6943 24 15.3066 23.6489 16.7681 23.0154C16.2832 22.2973 16 21.4317 16 20.5C16 18.0147 18.0147 16 20.5 16C21.4317 16 22.2973 16.2832 23.0154 16.7681Z" fill="#8EF5C3"/>
<path d="M16 8L8 16M8 16H14M8 16V10" stroke="#003921" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M20.5 24C22.433 24 24 22.433 24 20.5C24 18.567 22.433 17 20.5 17C18.567 17 17 18.567 17 20.5C17 22.433 18.567 24 20.5 24ZM21 19C21 18.7239 20.7761 18.5 20.5 18.5C20.2239 18.5 20 18.7239 20 19V20.5C20 20.7761 20.2239 21 20.5 21H21.5C21.7761 21 22 20.7761 22 20.5C22 20.2239 21.7761 20 21.5 20H21V19Z" fill="#F7D65D"/>
</g>
<defs>
<clipPath id="clip0_5094_29921">
<rect width="24" height="24" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1 KiB

View file

@ -0,0 +1,11 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_5094_29958)">
<circle cx="12" cy="12" r="12" fill="#8EF5C3"/>
<path d="M16 8L8 16M8 16H14M8 16V10" stroke="#003921" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
</g>
<defs>
<clipPath id="clip0_5094_29958">
<rect width="24" height="24" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 421 B

View file

@ -0,0 +1,14 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_5094_29938)">
<path d="M23.0154 16.7681C23.6489 15.3066 24 13.6943 24 12C24 5.37258 18.6274 0 12 0C5.37258 0 0 5.37258 0 12C0 18.6274 5.37258 24 12 24C13.6943 24 15.3066 23.6489 16.7681 23.0154C16.2832 22.2973 16 21.4317 16 20.5C16 18.0147 18.0147 16 20.5 16C21.4317 16 22.2973 16.2832 23.0154 16.7681Z" fill="#FFB4A9"/>
<path d="M8 16L16 8M16 8L10 8M16 8L16 14" stroke="#690001" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
<circle cx="20.5" cy="20.5" r="3.5" fill="#D34E50"/>
<path d="M19.4395 19.4395L20.5001 20.5001L21.5608 21.5608" stroke="#2A2D34" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M19.5 21.5605L20.5607 20.4999L21.6213 19.4392" stroke="#2A2D34" stroke-linecap="round" stroke-linejoin="round"/>
</g>
<defs>
<clipPath id="clip0_5094_29938">
<rect width="24" height="24" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 985 B

View file

@ -0,0 +1,13 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_5094_29933)">
<path d="M23.0154 16.7681C23.6489 15.3066 24 13.6943 24 12C24 5.37258 18.6274 0 12 0C5.37258 0 0 5.37258 0 12C0 18.6274 5.37258 24 12 24C13.6943 24 15.3066 23.6489 16.7681 23.0154C16.2832 22.2973 16 21.4317 16 20.5C16 18.0147 18.0147 16 20.5 16C21.4317 16 22.2973 16.2832 23.0154 16.7681Z" fill="#FFB4A9"/>
<path d="M8 16L16 8M16 8L10 8M16 8L16 14" stroke="#690001" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
<circle cx="20.5" cy="20.5" r="3.5" fill="#F7D65D"/>
<path d="M20.5 19V20.5H21.5" stroke="#2A2D34" stroke-linecap="round" stroke-linejoin="round"/>
</g>
<defs>
<clipPath id="clip0_5094_29933">
<rect width="24" height="24" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 833 B

View file

@ -0,0 +1,11 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_5094_29961)">
<circle cx="12" cy="12" r="12" fill="#FFB4A9"/>
<path d="M8 16L16 8M16 8L10 8M16 8L16 14" stroke="#690001" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
</g>
<defs>
<clipPath id="clip0_5094_29961">
<rect width="24" height="24" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 426 B

25
assets/svg/drd-icon.svg Normal file
View file

@ -0,0 +1,25 @@
<svg width="99" height="70" viewBox="0 0 99 70" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_5372_11232)">
<path d="M91.2807 31.334H36.3926C32.1291 31.334 28.6729 34.8203 28.6729 39.1208V62.2128C28.6729 66.5134 32.1291 69.9996 36.3926 69.9996H91.2807C95.5442 69.9996 99.0004 66.5134 99.0004 62.2128V39.1208C99.0004 34.8203 95.5442 31.334 91.2807 31.334Z" fill="#E1E2E3"/>
<path d="M93.2051 28.6192V59.8664C93.2051 62.0499 91.4525 63.8177 89.2879 63.8177H25.0787C22.9088 63.8177 21.1562 62.0499 21.1562 59.8611V28.6245C21.1562 26.441 22.9088 24.668 25.0787 24.668H77.9639L89.3035 24.789C91.2856 24.81 93.0226 26.2937 93.1947 28.2773C93.2051 28.3877 93.2103 28.4982 93.2103 28.614L93.2051 28.6192Z" stroke="#222222" stroke-width="3" stroke-miterlimit="10"/>
<path d="M48.665 38.6689V49.8177" stroke="#222222" stroke-width="3" stroke-miterlimit="10" stroke-linecap="round"/>
<path d="M43.877 41.457L53.4483 47.0288" stroke="#222222" stroke-width="3" stroke-miterlimit="10" stroke-linecap="round"/>
<path d="M53.4483 41.457L43.877 47.0288" stroke="#222222" stroke-width="3" stroke-miterlimit="10" stroke-linecap="round"/>
<path d="M32.5166 38.6689V49.8177" stroke="#222222" stroke-width="3" stroke-miterlimit="10" stroke-linecap="round"/>
<path d="M27.7285 41.457L37.2999 47.0288" stroke="#222222" stroke-width="3" stroke-miterlimit="10" stroke-linecap="round"/>
<path d="M37.2999 41.457L27.7285 47.0288" stroke="#222222" stroke-width="3" stroke-miterlimit="10" stroke-linecap="round"/>
<path d="M64.9658 38.6689V49.8177" stroke="#222222" stroke-width="3" stroke-miterlimit="10" stroke-linecap="round"/>
<path d="M60.1777 41.457L69.7491 47.0288" stroke="#222222" stroke-width="3" stroke-miterlimit="10" stroke-linecap="round"/>
<path d="M69.7491 41.457L60.1777 47.0288" stroke="#222222" stroke-width="3" stroke-miterlimit="10" stroke-linecap="round"/>
<path d="M81.0518 38.6689V49.8177" stroke="#222222" stroke-width="3" stroke-miterlimit="10" stroke-linecap="round"/>
<path d="M76.2686 41.457L85.84 47.0288" stroke="#222222" stroke-width="3" stroke-miterlimit="10" stroke-linecap="round"/>
<path d="M85.84 41.457L76.2686 47.0288" stroke="#222222" stroke-width="3" stroke-miterlimit="10" stroke-linecap="round"/>
<path d="M21.1565 50.8068V56.1681C11.9085 54.3214 4.21483 47.3396 1.69028 37.6902C1.62247 37.4272 1.78417 37.1589 2.04497 37.0957L6.15519 36.0855C6.40556 36.0224 6.65071 36.175 6.71852 36.4275C8.64845 43.6987 14.2818 49.0548 21.1565 50.8068V50.8068Z" stroke="#222222" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M50.6117 24.6681H45.2027C43.93 20.8221 41.541 17.4443 38.2654 14.9504C33.9778 11.6883 28.6888 10.2941 23.3684 11.0412C23.045 11.0886 22.7164 11.1412 22.3983 11.2043L26.4146 16.0711L11.5333 17.0076C11.0534 17.0339 10.6831 16.5867 10.803 16.1131L14.5273 1.68652L18.7105 6.74268C19.9885 6.34282 21.3081 6.05344 22.6538 5.86403C29.346 4.92751 36.0016 6.67428 41.3898 10.7781C45.9747 14.2822 49.1877 19.1384 50.6117 24.6734V24.6681Z" stroke="#222222" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
</g>
<defs>
<clipPath id="clip0_5372_11232">
<rect width="99" height="70" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 3.1 KiB

View file

@ -0,0 +1,4 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="24" height="24" rx="4" fill="#999999"/>
<path d="M4.11878 12.405C3.62916 12.8917 3.62678 13.6832 4.11346 14.1728C4.60014 14.6624 5.3916 14.6648 5.88122 14.1781L4.11878 12.405ZM13.2994 5.04199L14.5492 5.06674C14.5558 4.7329 14.4285 4.41028 14.1958 4.17083C13.9631 3.93137 13.6443 3.79497 13.3104 3.79204L13.2994 5.04199ZM8.52393 3.75005C7.8336 3.74399 7.26907 4.2987 7.26301 4.98903C7.25696 5.67936 7.81167 6.2439 8.502 6.24995L8.52393 3.75005ZM11.9581 9.64191C11.9444 10.3321 12.4928 10.9028 13.1831 10.9164C13.8733 10.9301 14.4439 10.3816 14.4576 9.69141L11.9581 9.64191ZM19.8812 11.595C20.3708 11.1083 20.3732 10.3168 19.8865 9.82721C19.3999 9.33759 18.6084 9.3352 18.1188 9.82189L19.8812 11.595ZM10.7006 18.958L9.45135 18.9148C9.4397 19.2518 9.56465 19.5791 9.79784 19.8226C10.031 20.0661 10.3527 20.205 10.6898 20.208L10.7006 18.958ZM15.5444 20.25C16.2348 20.2559 16.7992 19.7011 16.8052 19.0108C16.8112 18.3205 16.2564 17.756 15.5661 17.75L15.5444 20.25ZM12.1096 14.3765C12.1335 13.6866 11.5935 13.1079 10.9036 13.0841C10.2136 13.0602 9.63497 13.6002 9.61114 14.2902L12.1096 14.3765ZM5.88122 14.1781L14.1806 5.92853L12.4182 4.15545L4.11878 12.405L5.88122 14.1781ZM8.502 6.24995L13.2884 6.29194L13.3104 3.79204L8.52393 3.75005L8.502 6.24995ZM12.0496 5.01724L11.9581 9.64191L14.4576 9.69141L14.5492 5.06674L12.0496 5.01724ZM18.1188 9.82189L9.81938 18.0715L11.5818 19.8445L19.8812 11.595L18.1188 9.82189ZM15.5661 17.75L10.7114 17.708L10.6898 20.208L15.5444 20.25L15.5661 17.75ZM11.9499 19.0012L12.1096 14.3765L9.61114 14.2902L9.45135 18.9148L11.9499 19.0012Z" fill="#232323"/>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View file

Before

Width:  |  Height:  |  Size: 895 B

After

Width:  |  Height:  |  Size: 895 B

View file

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

View file

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View file

@ -0,0 +1,5 @@
<svg width="70" height="70" viewBox="0 0 70 70" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M41.3715 9.57675C37.2965 7.22564 32.2041 10.1695 32.2041 14.8717C32.2041 19.5739 34.4762 23.6489 38.2004 26.163L53.9717 35.3057L54.0112 35.2908L69.9948 26.0543L41.3715 9.57675Z" fill="#B3B3B3"/>
<path d="M38.2014 26.163C34.4771 23.6489 32.205 19.4159 32.205 14.8717C32.205 12.6342 33.3757 10.7671 35.0402 9.7101C34.9612 9.75455 35.1192 9.66564 35.0402 9.7101L10.0917 23.7279L6.08593 26.1481L3.35449 27.7188C5.07337 26.8446 7.22692 26.7754 9.14831 27.8917L16.0189 31.8037L22.0399 35.2859L38.0236 44.5076L53.9677 35.2958L38.1964 26.1531L38.2014 26.163Z" fill="#666666"/>
<path d="M70 44.5187L38.0278 62.9917L31.992 59.5095L31.9673 59.4848L6.06054 44.5187C4.28733 43.3629 2.84505 41.7872 1.82755 40.014C0.642111 37.9691 0 35.618 0 33.1829C0 30.9899 1.10147 29.1771 2.70181 28.1004C2.91914 27.967 3.13153 27.8435 3.35874 27.725C5.07762 26.8507 7.23116 26.7816 9.15256 27.8979L15.9836 31.8394L22.0047 35.3068L22.0442 35.292L38.0278 44.5137L53.9719 35.3019L70 44.5137V44.5187Z" fill="#232323"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View file

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

View file

Before

Width:  |  Height:  |  Size: 2 KiB

After

Width:  |  Height:  |  Size: 2 KiB

View file

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View file

Before

Width:  |  Height:  |  Size: 882 B

After

Width:  |  Height:  |  Size: 882 B

View file

Before

Width:  |  Height:  |  Size: 912 B

After

Width:  |  Height:  |  Size: 912 B

View file

Before

Width:  |  Height:  |  Size: 287 B

After

Width:  |  Height:  |  Size: 287 B

View file

Before

Width:  |  Height:  |  Size: 847 B

After

Width:  |  Height:  |  Size: 847 B

View file

Before

Width:  |  Height:  |  Size: 697 B

After

Width:  |  Height:  |  Size: 697 B

View file

Before

Width:  |  Height:  |  Size: 292 B

After

Width:  |  Height:  |  Size: 292 B

View file

@ -0,0 +1,10 @@
<svg width="22" height="22" viewBox="0 0 22 22" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_5241_16732)">
<path d="M19.25 0H2.75C1.2302 0 0 1.22977 0 2.71133V15.0477C0 16.6461 1.2302 17.8363 2.75 17.8363H6.875V21.407C6.875 21.8313 7.3584 22.0739 7.69656 21.8216L13.0625 17.8363H19.25C20.7702 17.8363 22 16.6061 22 15.125V2.71133C22 1.22977 20.7711 0 19.25 0ZM10.7035 13.75C10.1148 13.75 9.625 13.2602 9.625 12.6328C9.625 12.0055 10.1148 11.5156 10.7035 11.5156C11.3695 11.5156 11.8594 12.0055 11.8594 12.6328C11.8594 13.2602 11.3695 13.75 10.7035 13.75ZM13.2215 8.73984L11.5745 9.73371V9.8047C11.5745 10.2662 11.1806 10.6568 10.7151 10.6568C10.2498 10.6568 9.85574 10.2663 9.85574 9.8047V9.19961C9.85574 8.91563 9.99891 8.63156 10.2854 8.4541L12.3264 7.24711C12.577 7.14141 12.7188 6.89219 12.7188 6.60859C12.7188 6.1826 12.3606 5.82785 11.9311 5.82785H10.0676C9.63789 5.82785 9.27996 6.18277 9.27996 6.60859C9.27996 7.07008 8.88611 7.46066 8.42059 7.46066C7.95506 7.46066 7.5625 7.07266 7.5625 6.60859C7.5625 5.225 8.67109 4.125 10.0676 4.125H11.9294C13.3289 4.125 14.4375 5.225 14.4375 6.60859C14.4375 7.46367 13.9734 8.28008 13.2215 8.73984Z" fill="#232323"/>
</g>
<defs>
<clipPath id="clip0_5241_16732">
<rect width="22" height="22" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

10
assets/svg/minimize.svg Normal file
View file

@ -0,0 +1,10 @@
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_5203_31720)">
<path d="M1.28098 11.7793L4.12559 8.93633V10.1246C4.12559 10.5392 4.46098 10.8746 4.87559 10.8746C5.29019 10.8746 5.62559 10.5392 5.62559 10.1246V7.12461C5.62559 7.02702 5.60572 6.9298 5.56781 6.8382C5.49199 6.65352 5.34668 6.5082 5.16152 6.4332C5.07012 6.39336 4.97402 6.37461 4.87559 6.37461H1.87559C1.46098 6.37461 1.12559 6.71 1.12559 7.12461C1.12559 7.53922 1.46098 7.87461 1.87559 7.87461H3.06504L0.219727 10.7199C-0.0732422 11.0129 -0.0732422 11.4875 0.219727 11.7805C0.512695 12.0734 0.988008 12.0723 1.28098 11.7793ZM6.43418 5.16055C6.51016 5.3443 6.65634 5.49055 6.84012 5.56648C6.93105 5.60586 7.02715 5.62461 7.12559 5.62461H10.1256C10.5402 5.62461 10.8756 5.28922 10.8756 4.87461C10.8756 4.46 10.5402 4.12461 10.1256 4.12461H8.93613L11.7814 1.2793C12.0744 0.986328 12.0744 0.511719 11.7814 0.21875C11.4887 -0.0739843 11.0141 -0.0744531 10.7209 0.21875L7.87559 3.06523V1.87461C7.87559 1.46 7.54019 1.12461 7.12559 1.12461C6.71098 1.12461 6.37559 1.46 6.37559 1.87461V4.85352C6.37559 4.97305 6.39434 5.06914 6.43418 5.16055Z" fill="#E0E3E3"/>
</g>
<defs>
<clipPath id="clip0_5203_31720">
<rect width="12" height="12" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View file

@ -1,12 +0,0 @@
<svg width="102" height="102" viewBox="0 0 102 102" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_3358_84804)">
<path d="M60.2849 13.9547C54.3472 10.5288 46.9268 14.8184 46.9268 21.6702C46.9268 28.522 50.2375 34.4598 55.6643 38.1232L78.6452 51.4454L78.7028 51.4238L101.993 37.9649L60.2849 13.9547Z" fill="#B3B3B3"/>
<path d="M55.6646 38.1228C50.2378 34.4593 46.9271 28.2913 46.9271 21.6697C46.9271 18.4094 48.6328 15.6888 51.0583 14.1486C50.9431 14.2134 51.1735 14.0838 51.0583 14.1486L14.7048 34.5745L8.8678 38.1012L4.8877 40.3899C7.39235 39.116 10.5304 39.0152 13.3301 40.6418L23.3415 46.3421L32.115 51.4161L55.4055 64.8535L78.6383 51.4305L55.6574 38.1084L55.6646 38.1228Z" fill="#666666"/>
<path d="M102 64.8678L55.4119 91.7857L46.6168 86.7116L46.5809 86.6756L8.83108 64.8678C6.24725 63.1837 4.14564 60.8877 2.663 58.3039C0.935648 55.3242 0 51.8983 0 48.3501C0 45.1545 1.605 42.513 3.93692 40.944C4.2536 40.7497 4.56308 40.5698 4.89416 40.397C7.39882 39.1231 10.5368 39.0224 13.3366 40.649L23.2904 46.3924L32.0639 51.4449L32.1215 51.4233L55.4119 64.8606L78.6448 51.4377L102 64.8606V64.8678Z" fill="#232323"/>
</g>
<defs>
<clipPath id="clip0_3358_84804">
<rect width="102" height="102" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 1.2 KiB

4
assets/svg/wallet-fa.svg Normal file
View file

@ -0,0 +1,4 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M2.25 5.95781L21 6C21.0187 6 21.0422 6 21.0609 6C21.5859 6.01406 22.0734 6.16875 22.5 6.41719V6.40313C23.3953 6.91875 24 7.88906 24 9V19.5C24 21.1547 22.6547 22.5 21 22.5H3C1.34297 22.5 0 21.1547 0 19.5V3.75C0 4.99219 1.00734 6 2.25 6V5.95781ZM19.5 15.75C20.3297 15.75 21 15.0797 21 14.25C21 13.4203 20.3297 12.75 19.5 12.75C18.6703 12.75 18 13.4203 18 14.25C18 15.0797 18.6703 15.75 19.5 15.75Z" fill="#232323"/>
<path opacity="0.4" d="M0 3.75C0 2.50734 1.00734 1.5 2.25 1.5H20.25C21.4922 1.5 22.5 2.50734 22.5 3.75V6.40313C22.0594 6.14531 21.5484 6 21 6H2.25C1.00734 6 0 4.99219 0 3.75Z" fill="#232323"/>
</svg>

After

Width:  |  Height:  |  Size: 719 B

202
google_fonts/LICENSE.txt Normal file
View file

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -449,7 +449,7 @@
buildSettings = { buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = 51; CURRENT_PROJECT_VERSION = 63;
DEVELOPMENT_TEAM = 4DQKUWSG6C; DEVELOPMENT_TEAM = 4DQKUWSG6C;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = ( FRAMEWORK_SEARCH_PATHS = (
@ -503,7 +503,7 @@
"$(PROJECT_DIR)/../crypto_plugins/flutter_libmonero/cw_shared_external/ios/External/ios/**", "$(PROJECT_DIR)/../crypto_plugins/flutter_libmonero/cw_shared_external/ios/External/ios/**",
"$(PROJECT_DIR)/../crypto_plugins/flutter_libepiccash/ios/libs", "$(PROJECT_DIR)/../crypto_plugins/flutter_libepiccash/ios/libs",
); );
MARKETING_VERSION = 1.4.39; MARKETING_VERSION = 1.4.48;
ONLY_ACTIVE_ARCH = NO; ONLY_ACTIVE_ARCH = NO;
PRODUCT_BUNDLE_IDENTIFIER = com.cypherstack.stackwallet; PRODUCT_BUNDLE_IDENTIFIER = com.cypherstack.stackwallet;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
@ -633,7 +633,7 @@
buildSettings = { buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = 51; CURRENT_PROJECT_VERSION = 63;
DEVELOPMENT_TEAM = 4DQKUWSG6C; DEVELOPMENT_TEAM = 4DQKUWSG6C;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = ( FRAMEWORK_SEARCH_PATHS = (
@ -687,7 +687,7 @@
"$(PROJECT_DIR)/../crypto_plugins/flutter_libmonero/cw_shared_external/ios/External/ios/**", "$(PROJECT_DIR)/../crypto_plugins/flutter_libmonero/cw_shared_external/ios/External/ios/**",
"$(PROJECT_DIR)/../crypto_plugins/flutter_libepiccash/ios/libs", "$(PROJECT_DIR)/../crypto_plugins/flutter_libepiccash/ios/libs",
); );
MARKETING_VERSION = 1.4.39; MARKETING_VERSION = 1.4.48;
ONLY_ACTIVE_ARCH = NO; ONLY_ACTIVE_ARCH = NO;
PRODUCT_BUNDLE_IDENTIFIER = com.cypherstack.stackwallet; PRODUCT_BUNDLE_IDENTIFIER = com.cypherstack.stackwallet;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
@ -709,7 +709,7 @@
buildSettings = { buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = 51; CURRENT_PROJECT_VERSION = 63;
DEVELOPMENT_TEAM = 4DQKUWSG6C; DEVELOPMENT_TEAM = 4DQKUWSG6C;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = ( FRAMEWORK_SEARCH_PATHS = (
@ -763,7 +763,7 @@
"$(PROJECT_DIR)/../crypto_plugins/flutter_libmonero/cw_shared_external/ios/External/ios/**", "$(PROJECT_DIR)/../crypto_plugins/flutter_libmonero/cw_shared_external/ios/External/ios/**",
"$(PROJECT_DIR)/../crypto_plugins/flutter_libepiccash/ios/libs", "$(PROJECT_DIR)/../crypto_plugins/flutter_libepiccash/ios/libs",
); );
MARKETING_VERSION = 1.4.39; MARKETING_VERSION = 1.4.48;
ONLY_ACTIVE_ARCH = NO; ONLY_ACTIVE_ARCH = NO;
PRODUCT_BUNDLE_IDENTIFIER = com.cypherstack.stackwallet; PRODUCT_BUNDLE_IDENTIFIER = com.cypherstack.stackwallet;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";

View file

@ -9,7 +9,6 @@ import 'package:stackwallet/models/notification_model.dart';
import 'package:stackwallet/models/trade_wallet_lookup.dart'; import 'package:stackwallet/models/trade_wallet_lookup.dart';
import 'package:stackwallet/services/wallets_service.dart'; import 'package:stackwallet/services/wallets_service.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart';
import 'package:stackwallet/utilities/logger.dart'; import 'package:stackwallet/utilities/logger.dart';
class DB { class DB {
@ -30,6 +29,7 @@ class DB {
static const String boxNameWalletsToDeleteOnStart = "walletsToDeleteOnStart"; static const String boxNameWalletsToDeleteOnStart = "walletsToDeleteOnStart";
static const String boxNamePriceCache = "priceAPIPrice24hCache"; static const String boxNamePriceCache = "priceAPIPrice24hCache";
static const String boxNameDBInfo = "dbInfo"; static const String boxNameDBInfo = "dbInfo";
static const String boxNameTheme = "theme";
String boxNameTxCache({required Coin coin}) => "${coin.name}_txCache"; String boxNameTxCache({required Coin coin}) => "${coin.name}_txCache";
String boxNameSetCache({required Coin coin}) => String boxNameSetCache({required Coin coin}) =>

View file

@ -30,6 +30,7 @@ import 'package:stackwallet/pages/loading_view.dart';
import 'package:stackwallet/pages/pinpad_views/create_pin_view.dart'; import 'package:stackwallet/pages/pinpad_views/create_pin_view.dart';
import 'package:stackwallet/pages/pinpad_views/lock_screen_view.dart'; import 'package:stackwallet/pages/pinpad_views/lock_screen_view.dart';
import 'package:stackwallet/pages/settings_views/global_settings_view/stack_backup_views/restore_from_encrypted_string_view.dart'; import 'package:stackwallet/pages/settings_views/global_settings_view/stack_backup_views/restore_from_encrypted_string_view.dart';
import 'package:stackwallet/pages_desktop_specific/home/desktop_home_view.dart';
import 'package:stackwallet/providers/exchange/available_currencies_state_provider.dart'; import 'package:stackwallet/providers/exchange/available_currencies_state_provider.dart';
import 'package:stackwallet/providers/exchange/available_floating_rate_pairs_state_provider.dart'; import 'package:stackwallet/providers/exchange/available_floating_rate_pairs_state_provider.dart';
import 'package:stackwallet/providers/exchange/change_now_provider.dart'; import 'package:stackwallet/providers/exchange/change_now_provider.dart';
@ -42,6 +43,7 @@ import 'package:stackwallet/providers/global/base_currencies_provider.dart';
// import 'package:stackwallet/providers/global/has_authenticated_start_state_provider.dart'; // import 'package:stackwallet/providers/global/has_authenticated_start_state_provider.dart';
import 'package:stackwallet/providers/global/trades_service_provider.dart'; import 'package:stackwallet/providers/global/trades_service_provider.dart';
import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/providers/providers.dart';
import 'package:stackwallet/providers/ui/color_theme_provider.dart';
import 'package:stackwallet/route_generator.dart'; import 'package:stackwallet/route_generator.dart';
import 'package:stackwallet/services/debug_service.dart'; import 'package:stackwallet/services/debug_service.dart';
import 'package:stackwallet/services/locale_service.dart'; import 'package:stackwallet/services/locale_service.dart';
@ -50,13 +52,17 @@ import 'package:stackwallet/services/notifications_api.dart';
import 'package:stackwallet/services/notifications_service.dart'; import 'package:stackwallet/services/notifications_service.dart';
import 'package:stackwallet/services/trade_service.dart'; import 'package:stackwallet/services/trade_service.dart';
import 'package:stackwallet/services/wallets.dart'; import 'package:stackwallet/services/wallets.dart';
import 'package:stackwallet/utilities/cfcolors.dart';
import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/db_version_migration.dart'; import 'package:stackwallet/utilities/db_version_migration.dart';
import 'package:stackwallet/utilities/enums/backup_frequency_type.dart'; import 'package:stackwallet/utilities/enums/backup_frequency_type.dart';
import 'package:stackwallet/utilities/logger.dart'; import 'package:stackwallet/utilities/logger.dart';
import 'package:stackwallet/utilities/prefs.dart'; import 'package:stackwallet/utilities/prefs.dart';
import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/theme/color_theme.dart';
import 'package:stackwallet/utilities/theme/dark_colors.dart';
import 'package:stackwallet/utilities/theme/light_colors.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/utilities/util.dart';
import 'package:window_size/window_size.dart';
final openedFromSWBFileStringStateProvider = final openedFromSWBFileStringStateProvider =
StateProvider<String?>((ref) => null); StateProvider<String?>((ref) => null);
@ -66,6 +72,14 @@ final openedFromSWBFileStringStateProvider =
// miscellaneous box for later use // miscellaneous box for later use
void main() async { void main() async {
WidgetsBinding widgetsBinding = WidgetsFlutterBinding.ensureInitialized(); WidgetsBinding widgetsBinding = WidgetsFlutterBinding.ensureInitialized();
GoogleFonts.config.allowRuntimeFetching = false;
if (Util.isDesktop) {
setWindowTitle('Stack Wallet');
setWindowMinSize(const Size(1200, 900));
setWindowMaxSize(Size.infinite);
}
Directory appDirectory = (await getApplicationDocumentsDirectory()); Directory appDirectory = (await getApplicationDocumentsDirectory());
if (Platform.isIOS) { if (Platform.isIOS) {
appDirectory = (await getLibraryDirectory()); appDirectory = (await getLibraryDirectory());
@ -134,6 +148,8 @@ void main() async {
monero.onStartup(); monero.onStartup();
wownero.onStartup(); wownero.onStartup();
await Hive.openBox<dynamic>(DB.boxNameTheme);
// SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, // SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual,
// overlays: [SystemUiOverlay.bottom]); // overlays: [SystemUiOverlay.bottom]);
await NotificationApi.init(); await NotificationApi.init();
@ -337,6 +353,18 @@ class _MaterialAppWithThemeState extends ConsumerState<MaterialAppWithTheme>
@override @override
void initState() { void initState() {
final colorScheme = DB.instance
.get<dynamic>(boxName: DB.boxNameTheme, key: "colorScheme") as String?;
ThemeType themeType;
switch (colorScheme) {
case "dark":
themeType = ThemeType.dark;
break;
case "light":
default:
themeType = ThemeType.light;
}
loadingCompleter = Completer(); loadingCompleter = Completer();
WidgetsBinding.instance.addObserver(this); WidgetsBinding.instance.addObserver(this);
// load locale and prefs // load locale and prefs
@ -347,8 +375,12 @@ class _MaterialAppWithThemeState extends ConsumerState<MaterialAppWithTheme>
_prefs = ref.read(prefsChangeNotifierProvider); _prefs = ref.read(prefsChangeNotifierProvider);
_wallets = ref.read(walletsChangeNotifierProvider); _wallets = ref.read(walletsChangeNotifierProvider);
if (Platform.isAndroid) { WidgetsBinding.instance.addPostFrameCallback((_) async {
WidgetsBinding.instance.addPostFrameCallback((_) async { ref.read(colorThemeProvider.state).state =
StackColors.fromStackColorTheme(
themeType == ThemeType.dark ? DarkColors() : LightColors());
if (Platform.isAndroid) {
// fetch open file if it exists // fetch open file if it exists
await getOpenFile(); await getOpenFile();
@ -362,8 +394,8 @@ class _MaterialAppWithThemeState extends ConsumerState<MaterialAppWithTheme>
ref.read(openedFromSWBFileStringStateProvider.state).state = null; ref.read(openedFromSWBFileStringStateProvider.state).state = null;
} }
// ref.read(shouldShowLockscreenOnResumeStateProvider.state).state = false; // ref.read(shouldShowLockscreenOnResumeStateProvider.state).state = false;
}); }
} });
super.initState(); super.initState();
} }
@ -495,36 +527,45 @@ class _MaterialAppWithThemeState extends ConsumerState<MaterialAppWithTheme>
// addToDebugMessagesDB: false); // addToDebugMessagesDB: false);
// }); // });
final colorScheme = ref.watch(colorThemeProvider.state).state;
return MaterialApp( return MaterialApp(
key: GlobalKey(), key: GlobalKey(),
navigatorKey: navigatorKey, navigatorKey: navigatorKey,
title: 'Stack Wallet', title: 'Stack Wallet',
onGenerateRoute: RouteGenerator.generateRoute, onGenerateRoute: RouteGenerator.generateRoute,
theme: ThemeData( theme: ThemeData(
highlightColor: CFColors.splashLight, extensions: [colorScheme],
highlightColor: colorScheme.highlight,
brightness: Brightness.light, brightness: Brightness.light,
fontFamily: GoogleFonts.inter().fontFamily, fontFamily: GoogleFonts.inter().fontFamily,
textTheme: GoogleFonts.interTextTheme().copyWith( unselectedWidgetColor: colorScheme.radioButtonBorderDisabled,
button: STextStyles.button, // textTheme: GoogleFonts.interTextTheme().copyWith(
), // button: STextStyles.button(context),
// subtitle1: STextStyles.field(context).copyWith(
// color: colorScheme.textDark,
// ),
// ),
radioTheme: const RadioThemeData( radioTheme: const RadioThemeData(
splashRadius: 0, splashRadius: 0,
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
), ),
// splashFactory: NoSplash.splashFactory, // splashFactory: NoSplash.splashFactory,
splashColor: Colors.transparent, splashColor: Colors.transparent,
buttonTheme: const ButtonThemeData( buttonTheme: ButtonThemeData(
splashColor: CFColors.splashMed, splashColor: colorScheme.splash,
), ),
textButtonTheme: TextButtonThemeData( textButtonTheme: TextButtonThemeData(
style: ButtonStyle( style: ButtonStyle(
// splashFactory: NoSplash.splashFactory, // splashFactory: NoSplash.splashFactory,
overlayColor: MaterialStateProperty.all(CFColors.splashMed), overlayColor: MaterialStateProperty.all(colorScheme.splash),
minimumSize: MaterialStateProperty.all<Size>(const Size(46, 46)), minimumSize: MaterialStateProperty.all<Size>(const Size(46, 46)),
textStyle: MaterialStateProperty.all<TextStyle>(STextStyles.button), // textStyle: MaterialStateProperty.all<TextStyle>(
foregroundColor: MaterialStateProperty.all(CFColors.white), // STextStyles.button(context)),
backgroundColor: foregroundColor:
MaterialStateProperty.all<Color>(CFColors.buttonGray), MaterialStateProperty.all(colorScheme.buttonTextSecondary),
backgroundColor: MaterialStateProperty.all<Color>(
colorScheme.buttonBackSecondary),
shape: MaterialStateProperty.all<OutlinedBorder>( shape: MaterialStateProperty.all<OutlinedBorder>(
RoundedRectangleBorder( RoundedRectangleBorder(
// 1000 to be relatively sure it keeps its pill shape // 1000 to be relatively sure it keeps its pill shape
@ -533,8 +574,8 @@ class _MaterialAppWithThemeState extends ConsumerState<MaterialAppWithTheme>
), ),
), ),
), ),
primaryColor: CFColors.stackAccent, primaryColor: colorScheme.accentColorDark,
primarySwatch: CFColors.createMaterialColor(CFColors.stackAccent), primarySwatch: Util.createMaterialColor(colorScheme.accentColorDark),
checkboxTheme: CheckboxThemeData( checkboxTheme: CheckboxThemeData(
splashRadius: 0, splashRadius: 0,
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
@ -544,40 +585,44 @@ class _MaterialAppWithThemeState extends ConsumerState<MaterialAppWithTheme>
checkColor: MaterialStateColor.resolveWith( checkColor: MaterialStateColor.resolveWith(
(state) { (state) {
if (state.contains(MaterialState.selected)) { if (state.contains(MaterialState.selected)) {
return CFColors.white; return colorScheme.checkboxIconChecked;
} }
return CFColors.link2; return colorScheme.checkboxBGChecked;
}, },
), ),
fillColor: MaterialStateColor.resolveWith( fillColor: MaterialStateColor.resolveWith(
(states) { (states) {
if (states.contains(MaterialState.selected)) { if (states.contains(MaterialState.selected)) {
return CFColors.link2; return colorScheme.checkboxBGChecked;
} }
return CFColors.disabledButton; return colorScheme.checkboxBorderEmpty;
}, },
), ),
), ),
appBarTheme: const AppBarTheme( appBarTheme: AppBarTheme(
centerTitle: false, centerTitle: false,
color: CFColors.almostWhite, color: colorScheme.background,
elevation: 0, elevation: 0,
), ),
inputDecorationTheme: InputDecorationTheme( inputDecorationTheme: InputDecorationTheme(
focusColor: CFColors.fieldGray, focusColor: colorScheme.textFieldDefaultBG,
fillColor: CFColors.fieldGray, fillColor: colorScheme.textFieldDefaultBG,
filled: true, filled: true,
contentPadding: const EdgeInsets.symmetric( contentPadding: const EdgeInsets.symmetric(
vertical: 6, vertical: 6,
horizontal: 12, horizontal: 12,
), ),
labelStyle: STextStyles.fieldLabel, // labelStyle: STextStyles.fieldLabel(context),
hintStyle: STextStyles.fieldLabel, // hintStyle: STextStyles.fieldLabel(context),
enabledBorder: _buildOutlineInputBorder(CFColors.fieldGray), enabledBorder:
focusedBorder: _buildOutlineInputBorder(CFColors.fieldGray), _buildOutlineInputBorder(colorScheme.textFieldDefaultBG),
errorBorder: _buildOutlineInputBorder(CFColors.fieldGray), focusedBorder:
disabledBorder: _buildOutlineInputBorder(CFColors.fieldGray), _buildOutlineInputBorder(colorScheme.textFieldDefaultBG),
focusedErrorBorder: _buildOutlineInputBorder(CFColors.fieldGray), errorBorder: _buildOutlineInputBorder(colorScheme.textFieldDefaultBG),
disabledBorder:
_buildOutlineInputBorder(colorScheme.textFieldDefaultBG),
focusedErrorBorder:
_buildOutlineInputBorder(colorScheme.textFieldDefaultBG),
), ),
), ),
home: FutureBuilder( home: FutureBuilder(
@ -599,6 +644,14 @@ class _MaterialAppWithThemeState extends ConsumerState<MaterialAppWithTheme>
ref.read(prefsChangeNotifierProvider).startupWalletId; ref.read(prefsChangeNotifierProvider).startupWalletId;
} }
// TODO proper desktop auth view
if (Util.isDesktop) {
Future<void>.delayed(Duration.zero).then((value) =>
Navigator.of(context).pushNamedAndRemoveUntil(
DesktopHomeView.routeName, (route) => false));
return Container();
}
return LockscreenView( return LockscreenView(
isInitialAppLogin: true, isInitialAppLogin: true,
routeOnSuccess: HomeView.routeName, routeOnSuccess: HomeView.routeName,

View file

@ -1,9 +1,9 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart'; import 'package:flutter_svg/svg.dart';
import 'package:stackwallet/models/notification_model.dart'; import 'package:stackwallet/models/notification_model.dart';
import 'package:stackwallet/utilities/cfcolors.dart';
import 'package:stackwallet/utilities/format.dart'; import 'package:stackwallet/utilities/format.dart';
import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/widgets/rounded_container.dart'; import 'package:stackwallet/widgets/rounded_container.dart';
import 'package:stackwallet/widgets/rounded_white_container.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart';
@ -42,7 +42,9 @@ class NotificationCard extends StatelessWidget {
), ),
child: SvgPicture.asset( child: SvgPicture.asset(
notification.iconAssetName, notification.iconAssetName,
color: CFColors.stackAccent, color: Theme.of(context)
.extension<StackColors>()!
.accentColorDark,
width: 24, width: 24,
height: 24, height: 24,
), ),
@ -56,7 +58,7 @@ class NotificationCard extends StatelessWidget {
children: [ children: [
Text( Text(
notification.title, notification.title,
style: STextStyles.titleBold12, style: STextStyles.titleBold12(context),
), ),
const SizedBox( const SizedBox(
height: 2, height: 2,
@ -66,11 +68,11 @@ class NotificationCard extends StatelessWidget {
children: [ children: [
Text( Text(
notification.description, notification.description,
style: STextStyles.label, style: STextStyles.label(context),
), ),
Text( Text(
extractPrettyDateString(notification.date), extractPrettyDateString(notification.date),
style: STextStyles.label, style: STextStyles.label(context),
), ),
], ],
), ),
@ -83,7 +85,10 @@ class NotificationCard extends StatelessWidget {
if (notification.read) if (notification.read)
Positioned.fill( Positioned.fill(
child: RoundedContainer( child: RoundedContainer(
color: CFColors.almostWhite.withOpacity(0.5), color: Theme.of(context)
.extension<StackColors>()!
.background
.withOpacity(0.5),
), ),
), ),
], ],

View file

@ -2,9 +2,9 @@ import 'package:another_flushbar/flushbar.dart';
import 'package:another_flushbar/flushbar_route.dart' as flushRoute; import 'package:another_flushbar/flushbar_route.dart' as flushRoute;
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart'; import 'package:flutter_svg/svg.dart';
import 'package:stackwallet/utilities/cfcolors.dart';
import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/enums/flush_bar_type.dart'; import 'package:stackwallet/utilities/enums/flush_bar_type.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
Future<dynamic> showFloatingFlushBar({ Future<dynamic> showFloatingFlushBar({
required FlushBarType type, required FlushBarType type,
@ -19,16 +19,16 @@ Future<dynamic> showFloatingFlushBar({
Color fg; Color fg;
switch (type) { switch (type) {
case FlushBarType.success: case FlushBarType.success:
fg = CFColors.notificationGreenForeground; fg = Theme.of(context).extension<StackColors>()!.snackBarTextSuccess;
bg = CFColors.notificationGreenBackground; bg = Theme.of(context).extension<StackColors>()!.snackBarBackSuccess;
break; break;
case FlushBarType.info: case FlushBarType.info:
fg = CFColors.notificationBlueForeground; fg = Theme.of(context).extension<StackColors>()!.snackBarTextInfo;
bg = CFColors.notificationBlueBackground; bg = Theme.of(context).extension<StackColors>()!.snackBarBackInfo;
break; break;
case FlushBarType.warning: case FlushBarType.warning:
fg = CFColors.notificationRedForeground; fg = Theme.of(context).extension<StackColors>()!.snackBarTextError;
bg = CFColors.notificationRedBackground; bg = Theme.of(context).extension<StackColors>()!.snackBarBackError;
break; break;
} }
final bar = Flushbar<dynamic>( final bar = Flushbar<dynamic>(
@ -53,6 +53,7 @@ Future<dynamic> showFloatingFlushBar({
Constants.size.circularBorderRadius, Constants.size.circularBorderRadius,
), ),
margin: const EdgeInsets.all(20), margin: const EdgeInsets.all(20),
maxWidth: 550,
); );
final _route = flushRoute.showFlushbar<dynamic>( final _route = flushRoute.showFlushbar<dynamic>(

View file

@ -1,85 +1,223 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_svg/svg.dart';
import 'package:stackwallet/pages/add_wallet_views/add_wallet_view/sub_widgets/coin_select_item.dart'; import 'package:stackwallet/pages/add_wallet_views/add_wallet_view/sub_widgets/add_wallet_text.dart';
import 'package:stackwallet/pages/add_wallet_views/add_wallet_view/sub_widgets/mobile_coin_list.dart';
import 'package:stackwallet/pages/add_wallet_views/add_wallet_view/sub_widgets/next_button.dart'; import 'package:stackwallet/pages/add_wallet_views/add_wallet_view/sub_widgets/next_button.dart';
import 'package:stackwallet/providers/global/prefs_provider.dart'; import 'package:stackwallet/pages/add_wallet_views/add_wallet_view/sub_widgets/searchable_coin_list.dart';
import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/exit_to_my_stack_button.dart';
import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart';
import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/utilities/util.dart';
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart';
import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
import 'package:stackwallet/widgets/icon_widgets/x_icon.dart';
import 'package:stackwallet/widgets/rounded_white_container.dart';
import 'package:stackwallet/widgets/stack_text_field.dart';
import 'package:stackwallet/widgets/textfield_icon_button.dart';
class AddWalletView extends StatelessWidget { class AddWalletView extends StatefulWidget {
const AddWalletView({Key? key}) : super(key: key); const AddWalletView({Key? key}) : super(key: key);
static const routeName = "/addWallet"; static const routeName = "/addWallet";
@override @override
Widget build(BuildContext context) { State<AddWalletView> createState() => _AddWalletViewState();
List<Coin> coins = [...Coin.values]; }
coins.remove(Coin.firoTestNet);
return Scaffold(
appBar: AppBar(
leading: AppBarBackButton(
onPressed: () {
Navigator.of(context).pop();
},
),
),
body: Container(
color: CFColors.almostWhite,
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text(
"Add wallet",
textAlign: TextAlign.center,
style: STextStyles.pageTitleH1,
),
const SizedBox(
height: 16,
),
Text(
"Select wallet currency",
textAlign: TextAlign.center,
style: STextStyles.subtitle,
),
const SizedBox(
height: 16,
),
Expanded(
child: Consumer(
builder: (_, ref, __) {
bool showTestNet = ref.watch(
prefsChangeNotifierProvider
.select((value) => value.showTestNetCoins),
);
return ListView.builder( class _AddWalletViewState extends State<AddWalletView> {
itemCount: showTestNet late final TextEditingController _searchFieldController;
? coins.length late final FocusNode _searchFocusNode;
: coins.length - (kTestNetCoinCount),
itemBuilder: (ctx, index) { String _searchTerm = "";
return Padding(
padding: const EdgeInsets.all(4), final List<Coin> coins = [...Coin.values];
child: CoinSelectItem(
coin: coins[index], @override
void initState() {
_searchFieldController = TextEditingController();
_searchFocusNode = FocusNode();
coins.remove(Coin.firoTestNet);
super.initState();
}
@override
void dispose() {
_searchFieldController.dispose();
_searchFocusNode.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
debugPrint("BUILD: $runtimeType");
if (Util.isDesktop) {
return DesktopScaffold(
appBar: const DesktopAppBar(
isCompactHeight: false,
leading: AppBarBackButton(),
trailing: ExitToMyStackButton(),
),
body: Column(
children: [
const AddWalletText(
isDesktop: true,
),
const SizedBox(
height: 16,
),
Expanded(
child: SizedBox(
width: 480,
child: RoundedWhiteContainer(
radiusMultiplier: 2,
padding: const EdgeInsets.only(
left: 16,
top: 16,
right: 16,
bottom: 0,
),
child: Column(
children: [
Padding(
padding: const EdgeInsets.all(4.0),
child: ClipRRect(
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
), ),
); child: TextField(
}, controller: _searchFieldController,
); focusNode: _searchFocusNode,
}, onChanged: (value) {
setState(() {
_searchTerm = value;
});
},
style:
STextStyles.desktopTextMedium(context).copyWith(
height: 2,
),
decoration: standardInputDecoration(
"Search",
_searchFocusNode,
context,
).copyWith(
contentPadding: const EdgeInsets.symmetric(
vertical: 10,
),
prefixIcon: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 16,
// vertical: 20,
),
child: SvgPicture.asset(
Assets.svg.search,
width: 24,
height: 24,
color: Theme.of(context)
.extension<StackColors>()!
.textFieldDefaultSearchIconLeft,
),
),
suffixIcon: _searchFieldController.text.isNotEmpty
? Padding(
padding: const EdgeInsets.only(right: 10),
child: UnconstrainedBox(
child: Row(
children: [
TextFieldIconButton(
child: const XIcon(
width: 24,
height: 24,
),
onTap: () async {
setState(() {
_searchFieldController.text =
"";
_searchTerm = "";
});
},
),
],
),
),
)
: null,
),
),
),
),
Expanded(
child: SearchableCoinList(
coins: coins,
isDesktop: true,
searchTerm: _searchTerm,
),
),
],
),
), ),
), ),
const SizedBox( ),
height: 16, const SizedBox(
height: 16,
),
const SizedBox(
height: 70,
width: 480,
child: AddWalletNextButton(
isDesktop: true,
), ),
const AddWalletNextButton(), ),
], const SizedBox(
height: 32,
),
],
),
);
} else {
return Scaffold(
appBar: AppBar(
leading: AppBarBackButton(
onPressed: () {
Navigator.of(context).pop();
},
), ),
), ),
), body: Container(
); color: Theme.of(context).extension<StackColors>()!.background,
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const AddWalletText(
isDesktop: false,
),
const SizedBox(
height: 16,
),
Expanded(
child: MobileCoinList(
coins: coins,
isDesktop: false,
),
),
const SizedBox(
height: 16,
),
const AddWalletNextButton(
isDesktop: false,
),
],
),
),
),
);
}
} }
} }

View file

@ -0,0 +1,34 @@
import 'package:flutter/material.dart';
import 'package:stackwallet/utilities/text_styles.dart';
class AddWalletText extends StatelessWidget {
const AddWalletText({Key? key, required this.isDesktop}) : super(key: key);
final bool isDesktop;
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text(
"Add wallet",
textAlign: TextAlign.center,
style: isDesktop
? STextStyles.desktopH2(context)
: STextStyles.pageTitleH1(context),
),
const SizedBox(
height: 16,
),
Text(
"Select wallet currency",
textAlign: TextAlign.center,
style: isDesktop
? STextStyles.desktopSubtitleH2(context)
: STextStyles.subtitle(context),
),
],
);
}
}

View file

@ -3,10 +3,11 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/svg.dart'; import 'package:flutter_svg/svg.dart';
import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/providers/providers.dart';
import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/cfcolors.dart';
import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart';
import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/utilities/util.dart';
class CoinSelectItem extends ConsumerWidget { class CoinSelectItem extends ConsumerWidget {
const CoinSelectItem({ const CoinSelectItem({
@ -20,40 +21,70 @@ class CoinSelectItem extends ConsumerWidget {
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
debugPrint("BUILD: CoinSelectItem for ${coin.name}"); debugPrint("BUILD: CoinSelectItem for ${coin.name}");
final selectedCoin = ref.watch(addWalletSelectedCoinStateProvider); final selectedCoin = ref.watch(addWalletSelectedCoinStateProvider);
final isDesktop = Util.isDesktop;
return Container( return Container(
decoration: BoxDecoration( decoration: BoxDecoration(
// color: selectedCoin == coin ? CFColors.selection : CFColors.white, // color: selectedCoin == coin ? CFColors.selection : CFColors.white,
color: selectedCoin == coin ? CFColors.selected2 : CFColors.white, color: selectedCoin == coin
? Theme.of(context).extension<StackColors>()!.textFieldActiveBG
: Theme.of(context).extension<StackColors>()!.popupBG,
borderRadius: borderRadius:
BorderRadius.circular(Constants.size.circularBorderRadius), BorderRadius.circular(Constants.size.circularBorderRadius),
), ),
child: MaterialButton( child: MaterialButton(
// splashColor: CFColors.splashLight, // splashColor: Theme.of(context).extension<StackColors>()!.highlight,
key: Key("coinSelectItemButtonKey_${coin.name}"), key: Key("coinSelectItemButtonKey_${coin.name}"),
padding: const EdgeInsets.all(12), padding: isDesktop
? const EdgeInsets.only(left: 24)
: const EdgeInsets.all(12),
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: borderRadius:
BorderRadius.circular(Constants.size.circularBorderRadius), BorderRadius.circular(Constants.size.circularBorderRadius),
), ),
child: Row( child: ConstrainedBox(
children: [ constraints: BoxConstraints(
SvgPicture.asset( minHeight: isDesktop ? 70 : 0,
Assets.svg.iconFor(coin: coin), ),
width: 26, child: Row(
height: 26, children: [
), SvgPicture.asset(
const SizedBox( Assets.svg.iconFor(coin: coin),
width: 10, width: 26,
), height: 26,
Text(
coin.prettyName,
style: STextStyles.subtitle.copyWith(
fontWeight: FontWeight.w600,
fontSize: 14,
), ),
), SizedBox(
], width: isDesktop ? 12 : 10,
),
Text(
coin.prettyName,
style: isDesktop
? STextStyles.desktopTextMedium(context)
: STextStyles.subtitle600(context).copyWith(
fontSize: 14,
),
),
if (isDesktop && selectedCoin == coin) const Spacer(),
if (isDesktop && selectedCoin == coin)
Padding(
padding: const EdgeInsets.only(
right: 18,
),
child: SizedBox(
width: 24,
height: 24,
child: SvgPicture.asset(
Assets.svg.check,
color: Theme.of(context)
.extension<StackColors>()!
.accentColorDark,
),
),
),
],
),
), ),
onPressed: () => onPressed: () =>
ref.read(addWalletSelectedCoinStateProvider.state).state = coin, ref.read(addWalletSelectedCoinStateProvider.state).state = coin,

View file

@ -0,0 +1,40 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:stackwallet/pages/add_wallet_views/add_wallet_view/sub_widgets/coin_select_item.dart';
import 'package:stackwallet/providers/global/prefs_provider.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart';
class MobileCoinList extends StatelessWidget {
const MobileCoinList({
Key? key,
required this.coins,
required this.isDesktop,
}) : super(key: key);
final List<Coin> coins;
final bool isDesktop;
@override
Widget build(BuildContext context) {
return Consumer(
builder: (_, ref, __) {
bool showTestNet = ref.watch(
prefsChangeNotifierProvider.select((value) => value.showTestNetCoins),
);
return ListView.builder(
itemCount:
showTestNet ? coins.length : coins.length - (kTestNetCoinCount),
itemBuilder: (ctx, index) {
return Padding(
padding: const EdgeInsets.all(4),
child: CoinSelectItem(
coin: coins[index],
),
);
},
);
},
);
}
}

View file

@ -2,19 +2,27 @@ import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:stackwallet/pages/add_wallet_views/create_or_restore_wallet_view/create_or_restore_wallet_view.dart'; import 'package:stackwallet/pages/add_wallet_views/create_or_restore_wallet_view/create_or_restore_wallet_view.dart';
import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/providers/providers.dart';
import 'package:stackwallet/utilities/cfcolors.dart';
import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
class AddWalletNextButton extends ConsumerWidget { class AddWalletNextButton extends ConsumerWidget {
const AddWalletNextButton({Key? key}) : super(key: key); const AddWalletNextButton({
Key? key,
required this.isDesktop,
}) : super(key: key);
final bool isDesktop;
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
debugPrint("BUILD: NextButton"); debugPrint("BUILD: NextButton");
final selectedCoin = final selectedCoin =
ref.watch(addWalletSelectedCoinStateProvider.state).state; ref.watch(addWalletSelectedCoinStateProvider.state).state;
final enabled = selectedCoin != null;
return TextButton( return TextButton(
onPressed: selectedCoin == null onPressed: !enabled
? null ? null
: () { : () {
final selectedCoin = final selectedCoin =
@ -25,22 +33,20 @@ class AddWalletNextButton extends ConsumerWidget {
arguments: selectedCoin, arguments: selectedCoin,
); );
}, },
style: selectedCoin == null style: enabled
? Theme.of(context).textButtonTheme.style?.copyWith( ? Theme.of(context)
backgroundColor: MaterialStateProperty.all<Color>( .extension<StackColors>()!
CFColors.stackAccent.withOpacity( .getPrimaryEnabledButtonColor(context)
0.25, : Theme.of(context)
), .extension<StackColors>()!
), .getPrimaryDisabledButtonColor(context),
)
: Theme.of(context).textButtonTheme.style?.copyWith(
backgroundColor: MaterialStateProperty.all<Color>(
CFColors.stackAccent,
),
),
child: Text( child: Text(
"Next", "Next",
style: STextStyles.button, style: isDesktop
? enabled
? STextStyles.desktopButtonEnabled(context)
: STextStyles.desktopButtonDisabled(context)
: STextStyles.button(context),
), ),
); );
} }

View file

@ -0,0 +1,57 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:stackwallet/pages/add_wallet_views/add_wallet_view/sub_widgets/coin_select_item.dart';
import 'package:stackwallet/providers/global/prefs_provider.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart';
class SearchableCoinList extends ConsumerWidget {
const SearchableCoinList({
Key? key,
required this.coins,
required this.isDesktop,
required this.searchTerm,
}) : super(key: key);
final List<Coin> coins;
final bool isDesktop;
final String searchTerm;
List<Coin> filterCoins(String text, bool showTestNetCoins) {
final _coins = [...coins];
if (text.isNotEmpty) {
final lowercaseTerm = text.toLowerCase();
_coins.retainWhere((e) =>
e.ticker.toLowerCase().contains(lowercaseTerm) ||
e.prettyName.toLowerCase().contains(lowercaseTerm) ||
e.name.toLowerCase().contains(lowercaseTerm));
}
if (!showTestNetCoins) {
_coins.removeWhere((e) => e.name.endsWith("TestNet"));
}
// remove firo testnet regardless
_coins.remove(Coin.firoTestNet);
return _coins;
}
@override
Widget build(BuildContext context, WidgetRef ref) {
bool showTestNet = ref.watch(
prefsChangeNotifierProvider.select((value) => value.showTestNetCoins),
);
final _coins = filterCoins(searchTerm, showTestNet);
return ListView.builder(
itemCount: _coins.length,
itemBuilder: (ctx, index) {
return Padding(
padding: const EdgeInsets.all(4),
child: CoinSelectItem(
coin: _coins[index],
),
);
},
);
}
}

View file

@ -1,12 +1,15 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:stackwallet/pages/add_wallet_views/name_your_wallet_view/name_your_wallet_view.dart'; import 'package:stackwallet/pages/add_wallet_views/create_or_restore_wallet_view/sub_widgets/coin_image.dart';
import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/pages/add_wallet_views/create_or_restore_wallet_view/sub_widgets/create_or_restore_wallet_subtitle.dart';
import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:stackwallet/pages/add_wallet_views/create_or_restore_wallet_view/sub_widgets/create_or_restore_wallet_title.dart';
import 'package:stackwallet/utilities/enums/add_wallet_type_enum.dart'; import 'package:stackwallet/pages/add_wallet_views/create_or_restore_wallet_view/sub_widgets/create_wallet_button_group.dart';
import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/exit_to_my_stack_button.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart';
import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/utilities/util.dart';
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
import 'package:tuple/tuple.dart'; import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart';
import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
class CreateOrRestoreWalletView extends StatelessWidget { class CreateOrRestoreWalletView extends StatelessWidget {
const CreateOrRestoreWalletView({ const CreateOrRestoreWalletView({
@ -22,97 +25,105 @@ class CreateOrRestoreWalletView extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
debugPrint("BUILD: $runtimeType"); debugPrint("BUILD: $runtimeType");
return Scaffold( final isDesktop = Util.isDesktop;
appBar: AppBar(
leading: AppBarBackButton( if (isDesktop) {
onPressed: () { return DesktopScaffold(
Navigator.of(context).pop(); appBar: const DesktopAppBar(
}, isCompactHeight: false,
leading: AppBarBackButton(),
trailing: ExitToMyStackButton(),
), ),
), body: SizedBox(
body: Container( width: 480,
color: CFColors.almostWhite,
child: Padding(
padding: const EdgeInsets.all(16),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
Padding(
padding: const EdgeInsets.all(31),
child: Image(
image: AssetImage(
Assets.png.imageFor(coin: coin),
),
width: MediaQuery.of(context).size.width / 3,
),
),
const Spacer( const Spacer(
flex: 2, flex: 10,
), ),
Text( CreateRestoreWalletTitle(
"Add ${coin.prettyName} wallet", coin: coin,
textAlign: TextAlign.center, isDesktop: isDesktop,
style: STextStyles.pageTitleH1,
), ),
const SizedBox( const SizedBox(
height: 8, height: 16,
), ),
Text( SizedBox(
"Create a new wallet or restore an existing wallet from seed.", width: 324,
textAlign: TextAlign.center, child: CreateRestoreWalletSubTitle(
style: STextStyles.subtitle), isDesktop: isDesktop,
const Spacer(
flex: 5,
),
TextButton(
style: Theme.of(context).textButtonTheme.style?.copyWith(
backgroundColor: MaterialStateProperty.all<Color>(
CFColors.stackAccent,
),
),
onPressed: () {
Navigator.of(context).pushNamed(
NameYourWalletView.routeName,
arguments: Tuple2(
AddWalletType.New,
coin,
),
);
},
child: Text(
"Create new wallet",
style: STextStyles.button,
), ),
), ),
const SizedBox( const SizedBox(
height: 12, height: 32,
), ),
TextButton( CoinImage(
style: Theme.of(context).textButtonTheme.style?.copyWith( coin: coin,
backgroundColor: MaterialStateProperty.all<Color>( isDesktop: isDesktop,
CFColors.stackAccent.withOpacity(0.25), ),
), const SizedBox(
), height: 32,
onPressed: () { ),
Navigator.of(context).pushNamed( CreateWalletButtonGroup(
NameYourWalletView.routeName, coin: coin,
arguments: Tuple2( isDesktop: isDesktop,
AddWalletType.Restore, ),
coin, const Spacer(
), flex: 15,
);
},
child: Text(
"Restore wallet",
style: STextStyles.button.copyWith(
color: CFColors.stackAccent,
),
),
), ),
], ],
), ),
), ),
), );
); } else {
return Scaffold(
appBar: AppBar(
leading: AppBarBackButton(
onPressed: () {
Navigator.of(context).pop();
},
),
),
body: Container(
color: Theme.of(context).extension<StackColors>()!.background,
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Padding(
padding: const EdgeInsets.all(31),
child: CoinImage(
coin: coin,
isDesktop: isDesktop,
),
),
const Spacer(
flex: 2,
),
CreateRestoreWalletTitle(
coin: coin,
isDesktop: isDesktop,
),
const SizedBox(
height: 8,
),
CreateRestoreWalletSubTitle(
isDesktop: isDesktop,
),
const Spacer(
flex: 5,
),
CreateWalletButtonGroup(
coin: coin,
isDesktop: isDesktop,
),
],
),
),
),
);
}
} }
} }

View file

@ -0,0 +1,24 @@
import 'package:flutter/material.dart';
import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart';
class CoinImage extends StatelessWidget {
const CoinImage({
Key? key,
required this.coin,
required this.isDesktop,
}) : super(key: key);
final Coin coin;
final bool isDesktop;
@override
Widget build(BuildContext context) {
return Image(
image: AssetImage(
Assets.png.imageFor(coin: coin),
),
width: isDesktop ? 324 : MediaQuery.of(context).size.width / 3,
);
}
}

View file

@ -0,0 +1,22 @@
import 'package:flutter/material.dart';
import 'package:stackwallet/utilities/text_styles.dart';
class CreateRestoreWalletSubTitle extends StatelessWidget {
const CreateRestoreWalletSubTitle({
Key? key,
required this.isDesktop,
}) : super(key: key);
final bool isDesktop;
@override
Widget build(BuildContext context) {
return Text(
"Create a new wallet or restore an existing wallet from seed.",
textAlign: TextAlign.center,
style: isDesktop
? STextStyles.desktopSubtitleH2(context)
: STextStyles.subtitle(context),
);
}
}

View file

@ -0,0 +1,25 @@
import 'package:flutter/material.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart';
import 'package:stackwallet/utilities/text_styles.dart';
class CreateRestoreWalletTitle extends StatelessWidget {
const CreateRestoreWalletTitle({
Key? key,
required this.coin,
required this.isDesktop,
}) : super(key: key);
final Coin coin;
final bool isDesktop;
@override
Widget build(BuildContext context) {
return Text(
"Add ${coin.prettyName} wallet",
textAlign: TextAlign.center,
style: isDesktop
? STextStyles.desktopH2(context)
: STextStyles.pageTitleH1(context),
);
}
}

View file

@ -0,0 +1,86 @@
import 'package:flutter/material.dart';
import 'package:stackwallet/pages/add_wallet_views/name_your_wallet_view/name_your_wallet_view.dart';
import 'package:stackwallet/utilities/enums/add_wallet_type_enum.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart';
import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:tuple/tuple.dart';
class CreateWalletButtonGroup extends StatelessWidget {
const CreateWalletButtonGroup({
Key? key,
required this.coin,
required this.isDesktop,
}) : super(key: key);
final Coin coin;
final bool isDesktop;
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment:
isDesktop ? CrossAxisAlignment.center : CrossAxisAlignment.stretch,
children: [
ConstrainedBox(
constraints: BoxConstraints(
minHeight: isDesktop ? 70 : 0,
minWidth: isDesktop ? 480 : 0,
),
child: TextButton(
style: Theme.of(context)
.extension<StackColors>()!
.getPrimaryEnabledButtonColor(context),
onPressed: () {
Navigator.of(context).pushNamed(
NameYourWalletView.routeName,
arguments: Tuple2(
AddWalletType.New,
coin,
),
);
},
child: Text(
"Create new wallet",
style: isDesktop
? STextStyles.desktopButtonEnabled(context)
: STextStyles.button(context),
),
),
),
SizedBox(
height: isDesktop ? 16 : 12,
),
ConstrainedBox(
constraints: BoxConstraints(
minHeight: isDesktop ? 70 : 0,
minWidth: isDesktop ? 480 : 0,
),
child: TextButton(
style: Theme.of(context)
.extension<StackColors>()!
.getSecondaryEnabledButtonColor(context),
onPressed: () {
Navigator.of(context).pushNamed(
NameYourWalletView.routeName,
arguments: Tuple2(
AddWalletType.Restore,
coin,
),
);
},
child: Text(
"Restore wallet",
style: isDesktop
? STextStyles.desktopButtonSecondaryEnabled(context)
: STextStyles.button(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.accentColorDark),
),
),
),
],
);
}
}

View file

@ -1,19 +1,25 @@
import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:stackwallet/notifications/show_flush_bar.dart'; import 'package:stackwallet/notifications/show_flush_bar.dart';
import 'package:stackwallet/pages/add_wallet_views/new_wallet_recovery_phrase_warning_view/new_wallet_recovery_phrase_warning_view.dart'; import 'package:stackwallet/pages/add_wallet_views/new_wallet_recovery_phrase_warning_view/new_wallet_recovery_phrase_warning_view.dart';
import 'package:stackwallet/pages/add_wallet_views/restore_wallet_view/restore_options_view.dart'; import 'package:stackwallet/pages/add_wallet_views/restore_wallet_view/restore_options_view/restore_options_view.dart';
import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/exit_to_my_stack_button.dart';
import 'package:stackwallet/providers/global/wallets_service_provider.dart'; import 'package:stackwallet/providers/global/wallets_service_provider.dart';
import 'package:stackwallet/providers/ui/verify_recovery_phrase/mnemonic_word_count_state_provider.dart'; import 'package:stackwallet/providers/ui/verify_recovery_phrase/mnemonic_word_count_state_provider.dart';
import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/cfcolors.dart';
import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/enums/add_wallet_type_enum.dart'; import 'package:stackwallet/utilities/enums/add_wallet_type_enum.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart';
import 'package:stackwallet/utilities/enums/flush_bar_type.dart'; import 'package:stackwallet/utilities/enums/flush_bar_type.dart';
import 'package:stackwallet/utilities/name_generator.dart'; import 'package:stackwallet/utilities/name_generator.dart';
import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/utilities/util.dart';
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart';
import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
import 'package:stackwallet/widgets/icon_widgets/dice_icon.dart'; import 'package:stackwallet/widgets/icon_widgets/dice_icon.dart';
import 'package:stackwallet/widgets/icon_widgets/x_icon.dart'; import 'package:stackwallet/widgets/icon_widgets/x_icon.dart';
import 'package:stackwallet/widgets/rounded_white_container.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart';
@ -21,14 +27,6 @@ import 'package:stackwallet/widgets/stack_text_field.dart';
import 'package:stackwallet/widgets/textfield_icon_button.dart'; import 'package:stackwallet/widgets/textfield_icon_button.dart';
import 'package:tuple/tuple.dart'; import 'package:tuple/tuple.dart';
// TODO replace with real list and move out of this file
const kWalletNameWordList = [
"Bubby",
"Baby",
"Bobby",
"Booby",
];
class NameYourWalletView extends ConsumerStatefulWidget { class NameYourWalletView extends ConsumerStatefulWidget {
const NameYourWalletView({ const NameYourWalletView({
Key? key, Key? key,
@ -59,6 +57,8 @@ class _NameYourWalletViewState extends ConsumerState<NameYourWalletView> {
Set<String> namesToExclude = {}; Set<String> namesToExclude = {};
late final NameGenerator generator; late final NameGenerator generator;
late final bool isDesktop;
Future<String> _generateRandomWalletName() async { Future<String> _generateRandomWalletName() async {
final name = generator.generate(namesToExclude: namesToExclude); final name = generator.generate(namesToExclude: namesToExclude);
namesToExclude.add(name); namesToExclude.add(name);
@ -67,6 +67,8 @@ class _NameYourWalletViewState extends ConsumerState<NameYourWalletView> {
@override @override
void initState() { void initState() {
isDesktop = Util.isDesktop;
ref.read(walletsServiceChangeNotifierProvider).walletNames.then( ref.read(walletsServiceChangeNotifierProvider).walletNames.then(
(value) => namesToExclude.addAll( (value) => namesToExclude.addAll(
value.values.map((e) => e.name), value.values.map((e) => e.name),
@ -92,231 +94,278 @@ class _NameYourWalletViewState extends ConsumerState<NameYourWalletView> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
debugPrint( debugPrint(
"BUILD: NameYourWalletView with ${coin.name} ${addWalletType.name}"); "BUILD: NameYourWalletView with ${coin.name} ${addWalletType.name}");
return Scaffold(
appBar: AppBar( if (isDesktop) {
leading: AppBarBackButton( return DesktopScaffold(
onPressed: () { appBar: const DesktopAppBar(
if (textFieldFocusNode.hasFocus) { leading: AppBarBackButton(),
textFieldFocusNode.unfocus(); trailing: ExitToMyStackButton(),
Future<void>.delayed(const Duration(milliseconds: 100)) isCompactHeight: false,
.then((value) => Navigator.of(context).pop());
} else {
if (mounted) {
Navigator.of(context).pop();
}
}
},
), ),
), body: SizedBox(
body: Container( width: 480,
color: CFColors.almostWhite, child: _content(),
child: Padding( ),
padding: const EdgeInsets.all(16), );
child: LayoutBuilder( } else {
builder: (ctx, constraints) { return Scaffold(
return SingleChildScrollView( appBar: AppBar(
child: ConstrainedBox( leading: AppBarBackButton(
constraints: BoxConstraints(minHeight: constraints.maxHeight), onPressed: () {
child: IntrinsicHeight( if (textFieldFocusNode.hasFocus) {
child: Column( textFieldFocusNode.unfocus();
crossAxisAlignment: CrossAxisAlignment.stretch, Future<void>.delayed(const Duration(milliseconds: 100))
.then((value) => Navigator.of(context).pop());
} else {
if (mounted) {
Navigator.of(context).pop();
}
}
},
),
),
body: Container(
color: Theme.of(context).extension<StackColors>()!.background,
child: Padding(
padding: const EdgeInsets.all(16),
child: LayoutBuilder(
builder: (ctx, constraints) {
return SingleChildScrollView(
child: ConstrainedBox(
constraints:
BoxConstraints(minHeight: constraints.maxHeight),
child: IntrinsicHeight(
child: _content(),
),
),
);
},
),
),
),
);
}
}
Widget _content() => Column(
crossAxisAlignment:
isDesktop ? CrossAxisAlignment.center : CrossAxisAlignment.stretch,
children: [
if (isDesktop)
const Spacer(
flex: 10,
),
if (!isDesktop)
const Spacer(
flex: 1,
),
if (!isDesktop)
Image(
image: AssetImage(
Assets.png.imageFor(coin: coin),
),
height: 100,
),
SizedBox(
height: isDesktop ? 0 : 16,
),
Text(
"Name your ${coin.prettyName} wallet",
textAlign: TextAlign.center,
style: isDesktop
? STextStyles.desktopH2(context)
: STextStyles.pageTitleH1(context),
),
SizedBox(
height: isDesktop ? 16 : 8,
),
Text(
"Enter a label for your wallet (e.g. Savings)",
textAlign: TextAlign.center,
style: isDesktop
? STextStyles.desktopSubtitleH2(context)
: STextStyles.subtitle(context),
),
SizedBox(
height: isDesktop ? 40 : 16,
),
ClipRRect(
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
),
child: TextField(
onChanged: (string) {
if (string.isEmpty) {
if (_nextEnabled) {
setState(() {
_nextEnabled = false;
_showDiceIcon = true;
});
}
} else {
if (!_nextEnabled) {
setState(() {
_nextEnabled = true;
_showDiceIcon = false;
});
}
}
},
focusNode: textFieldFocusNode,
controller: textEditingController,
style: isDesktop
? STextStyles.desktopTextMedium(context).copyWith(
height: 2,
)
: STextStyles.field(context),
decoration: standardInputDecoration(
"Enter wallet name",
textFieldFocusNode,
context,
).copyWith(
suffixIcon: Padding(
padding: EdgeInsets.only(right: isDesktop ? 6 : 0),
child: UnconstrainedBox(
child: Row(
children: [ children: [
const Spacer( TextFieldIconButton(
flex: 1, key: const Key("genRandomWalletNameButtonKey"),
), child: _showDiceIcon
Image( ? DiceIcon(
image: AssetImage( width: isDesktop ? 20 : 17,
Assets.png.imageFor(coin: coin), height: isDesktop ? 20 : 17,
), )
height: 100, : XIcon(
), width: isDesktop ? 21 : 18,
const SizedBox( height: isDesktop ? 21 : 18,
height: 16,
),
Text(
"Name your ${coin.prettyName} wallet",
textAlign: TextAlign.center,
style: STextStyles.pageTitleH1,
),
const SizedBox(
height: 8,
),
Text(
"Enter a label for your wallet (e.g. Savings)",
textAlign: TextAlign.center,
style: STextStyles.subtitle,
),
const SizedBox(
height: 16,
),
ClipRRect(
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
),
child: TextField(
onChanged: (string) {
if (string.isEmpty) {
if (_nextEnabled) {
setState(() {
_nextEnabled = false;
_showDiceIcon = true;
});
}
} else {
if (!_nextEnabled) {
setState(() {
_nextEnabled = true;
_showDiceIcon = false;
});
}
}
},
focusNode: textFieldFocusNode,
controller: textEditingController,
style: STextStyles.field,
decoration: standardInputDecoration(
"Enter wallet name",
textFieldFocusNode,
).copyWith(
suffixIcon: Padding(
padding: const EdgeInsets.only(right: 0),
child: UnconstrainedBox(
child: Row(
children: [
TextFieldIconButton(
key: const Key(
"genRandomWalletNameButtonKey"),
child: _showDiceIcon
? const DiceIcon()
: const XIcon(),
onTap: () async {
if (_showDiceIcon) {
textEditingController.text =
await _generateRandomWalletName();
setState(() {
_nextEnabled = true;
_showDiceIcon = false;
});
} else {
textEditingController.text = "";
setState(() {
_nextEnabled = false;
_showDiceIcon = true;
});
}
},
)
],
),
), ),
), onTap: () async {
), if (_showDiceIcon) {
), textEditingController.text =
), await _generateRandomWalletName();
const SizedBox( setState(() {
height: 8, _nextEnabled = true;
), _showDiceIcon = false;
RoundedWhiteContainer( });
child: Center( } else {
child: Text( textEditingController.text = "";
"Roll the dice to pick a random name.", setState(() {
style: STextStyles.itemSubtitle, _nextEnabled = false;
), _showDiceIcon = true;
), });
), }
const Spacer( },
flex: 4, )
),
TextButton(
onPressed: _nextEnabled
? () async {
final walletsService = ref.read(
walletsServiceChangeNotifierProvider);
final name = textEditingController.text;
if (await walletsService
.checkForDuplicate(name)) {
showFloatingFlushBar(
type: FlushBarType.warning,
message: "Wallet name already in use.",
iconAsset: Assets.svg.circleAlert,
context: context,
);
} else {
// hide keyboard if has focus
if (FocusScope.of(context).hasFocus) {
FocusScope.of(context).unfocus();
await Future<void>.delayed(
const Duration(milliseconds: 50));
}
if (mounted) {
switch (widget.addWalletType) {
case AddWalletType.New:
Navigator.of(context).pushNamed(
NewWalletRecoveryPhraseWarningView
.routeName,
arguments: Tuple2(
name,
coin,
),
);
break;
case AddWalletType.Restore:
ref
.read(
mnemonicWordCountStateProvider
.state)
.state = Constants
.possibleLengthsForCoin(coin)
.first;
Navigator.of(context).pushNamed(
RestoreOptionsView.routeName,
arguments: Tuple2(
name,
coin,
),
);
break;
}
}
}
}
: null,
style: _nextEnabled
? Theme.of(context)
.textButtonTheme
.style
?.copyWith(
backgroundColor:
MaterialStateProperty.all<Color>(
CFColors.stackAccent,
))
: Theme.of(context)
.textButtonTheme
.style
?.copyWith(
backgroundColor:
MaterialStateProperty.all<Color>(
CFColors.stackAccent.withOpacity(
0.25,
),
),
),
child: Text(
"Next",
style: STextStyles.button,
),
),
], ],
), ),
), ),
), ),
); ),
}, ),
), ),
), SizedBox(
), height: isDesktop ? 16 : 8,
); ),
} RoundedWhiteContainer(
child: Center(
child: Text(
"Roll the dice to pick a random name.",
style: isDesktop
? STextStyles.desktopTextExtraSmall(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textSubtitle1,
)
: STextStyles.itemSubtitle(context),
),
),
),
if (!isDesktop)
const Spacer(
flex: 4,
),
if (isDesktop)
const SizedBox(
height: 32,
),
ConstrainedBox(
constraints: BoxConstraints(
minWidth: isDesktop ? 480 : 0,
minHeight: isDesktop ? 70 : 0,
),
child: TextButton(
onPressed: _nextEnabled
? () async {
final walletsService =
ref.read(walletsServiceChangeNotifierProvider);
final name = textEditingController.text;
if (await walletsService.checkForDuplicate(name)) {
unawaited(showFloatingFlushBar(
type: FlushBarType.warning,
message: "Wallet name already in use.",
iconAsset: Assets.svg.circleAlert,
context: context,
));
} else {
// hide keyboard if has focus
if (FocusScope.of(context).hasFocus) {
FocusScope.of(context).unfocus();
await Future<void>.delayed(
const Duration(milliseconds: 50));
}
if (mounted) {
switch (widget.addWalletType) {
case AddWalletType.New:
unawaited(Navigator.of(context).pushNamed(
NewWalletRecoveryPhraseWarningView.routeName,
arguments: Tuple2(
name,
coin,
),
));
break;
case AddWalletType.Restore:
ref
.read(mnemonicWordCountStateProvider.state)
.state = Constants.possibleLengthsForCoin(
coin)
.first;
unawaited(Navigator.of(context).pushNamed(
RestoreOptionsView.routeName,
arguments: Tuple2(
name,
coin,
),
));
break;
}
}
}
}
: null,
style: _nextEnabled
? Theme.of(context)
.extension<StackColors>()!
.getPrimaryEnabledButtonColor(context)
: Theme.of(context)
.extension<StackColors>()!
.getPrimaryDisabledButtonColor(context),
child: Text(
"Next",
style: isDesktop
? _nextEnabled
? STextStyles.desktopButtonEnabled(context)
: STextStyles.desktopButtonDisabled(context)
: STextStyles.button(context),
),
),
),
if (isDesktop)
const Spacer(
flex: 15,
),
],
);
} }

View file

@ -1,3 +1,4 @@
import 'dart:async';
import 'dart:math'; import 'dart:math';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -8,15 +9,20 @@ import 'package:stackwallet/notifications/show_flush_bar.dart';
import 'package:stackwallet/pages/add_wallet_views/new_wallet_recovery_phrase_view/sub_widgets/mnemonic_table.dart'; import 'package:stackwallet/pages/add_wallet_views/new_wallet_recovery_phrase_view/sub_widgets/mnemonic_table.dart';
import 'package:stackwallet/pages/add_wallet_views/new_wallet_recovery_phrase_warning_view/new_wallet_recovery_phrase_warning_view.dart'; import 'package:stackwallet/pages/add_wallet_views/new_wallet_recovery_phrase_warning_view/new_wallet_recovery_phrase_warning_view.dart';
import 'package:stackwallet/pages/add_wallet_views/verify_recovery_phrase_view/verify_recovery_phrase_view.dart'; import 'package:stackwallet/pages/add_wallet_views/verify_recovery_phrase_view/verify_recovery_phrase_view.dart';
import 'package:stackwallet/pages_desktop_specific/home/desktop_home_view.dart';
import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/exit_to_my_stack_button.dart';
import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/providers/providers.dart';
import 'package:stackwallet/services/coins/manager.dart'; import 'package:stackwallet/services/coins/manager.dart';
import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/cfcolors.dart';
import 'package:stackwallet/utilities/clipboard_interface.dart'; import 'package:stackwallet/utilities/clipboard_interface.dart';
import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/enums/flush_bar_type.dart'; import 'package:stackwallet/utilities/enums/flush_bar_type.dart';
import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/utilities/util.dart';
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart';
import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
import 'package:tuple/tuple.dart'; import 'package:tuple/tuple.dart';
class NewWalletRecoveryPhraseView extends ConsumerStatefulWidget { class NewWalletRecoveryPhraseView extends ConsumerStatefulWidget {
@ -46,12 +52,14 @@ class _NewWalletRecoveryPhraseViewState
late Manager _manager; late Manager _manager;
late List<String> _mnemonic; late List<String> _mnemonic;
late ClipboardInterface _clipboardInterface; late ClipboardInterface _clipboardInterface;
late final bool isDesktop;
@override @override
void initState() { void initState() {
_manager = widget.manager; _manager = widget.manager;
_mnemonic = widget.mnemonic; _mnemonic = widget.mnemonic;
_clipboardInterface = widget.clipboardInterface; _clipboardInterface = widget.clipboardInterface;
isDesktop = Util.isDesktop;
super.initState(); super.initState();
} }
@ -67,139 +75,243 @@ class _NewWalletRecoveryPhraseViewState
await _manager.exitCurrentWallet(); await _manager.exitCurrentWallet();
} }
Future<void> _copy() async {
final words = await _manager.mnemonic;
await _clipboardInterface.setData(ClipboardData(text: words.join(" ")));
unawaited(showFloatingFlushBar(
type: FlushBarType.info,
message: "Copied to clipboard",
iconAsset: Assets.svg.copy,
context: context,
));
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
debugPrint("BUILD: $runtimeType"); debugPrint("BUILD: $runtimeType");
return WillPopScope( return WillPopScope(
onWillPop: onWillPop, onWillPop: onWillPop,
child: Scaffold( child: MasterScaffold(
appBar: AppBar( isDesktop: isDesktop,
leading: AppBarBackButton( appBar: isDesktop
onPressed: () async { ? DesktopAppBar(
await delete(); isCompactHeight: false,
leading: AppBarBackButton(
if (mounted) {
Navigator.of(context).popUntil(
ModalRoute.withName(
NewWalletRecoveryPhraseWarningView.routeName,
),
);
}
// Navigator.of(context).pop();
},
),
actions: [
Padding(
padding: const EdgeInsets.all(10),
child: AspectRatio(
aspectRatio: 1,
child: AppBarIconButton(
color: CFColors.almostWhite,
shadows: const [],
icon: SvgPicture.asset(
Assets.svg.copy,
width: 24,
height: 24,
),
onPressed: () async { onPressed: () async {
final words = await _manager.mnemonic; await delete();
await _clipboardInterface
.setData(ClipboardData(text: words.join(" "))); if (mounted) {
showFloatingFlushBar( Navigator.of(context).popUntil(
type: FlushBarType.info, ModalRoute.withName(
message: "Copied to clipboard", NewWalletRecoveryPhraseWarningView.routeName,
iconAsset: Assets.svg.copy, ),
context: context, );
); }
// Navigator.of(context).pop();
}, },
), ),
trailing: ExitToMyStackButton(
onPressed: () async {
await delete();
if (mounted) {
Navigator.of(context).popUntil(
ModalRoute.withName(DesktopHomeView.routeName),
);
}
},
),
)
: AppBar(
leading: AppBarBackButton(
onPressed: () async {
await delete();
if (mounted) {
Navigator.of(context).popUntil(
ModalRoute.withName(
NewWalletRecoveryPhraseWarningView.routeName,
),
);
}
},
),
actions: [
Padding(
padding: const EdgeInsets.all(10),
child: AspectRatio(
aspectRatio: 1,
child: AppBarIconButton(
color: Theme.of(context)
.extension<StackColors>()!
.background,
shadows: const [],
icon: SvgPicture.asset(
Assets.svg.copy,
width: 24,
height: 24,
color: Theme.of(context)
.extension<StackColors>()!
.topNavIconPrimary,
),
onPressed: () async {
await _copy();
},
),
),
),
],
), ),
),
],
),
body: Container( body: Container(
color: CFColors.almostWhite, color: Theme.of(context).extension<StackColors>()!.background,
width: isDesktop ? 600 : null,
child: Padding( child: Padding(
padding: const EdgeInsets.all(16), padding:
isDesktop ? const EdgeInsets.all(0) : const EdgeInsets.all(16),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.stretch,
children: [ children: [
const SizedBox( if (isDesktop)
height: 4, const Spacer(
), flex: 10,
Text(
_manager.walletName,
textAlign: TextAlign.center,
style: STextStyles.label.copyWith(
fontSize: 12,
), ),
), if (!isDesktop)
const SizedBox( const SizedBox(
height: 4, height: 4,
),
if (!isDesktop)
Text(
_manager.walletName,
textAlign: TextAlign.center,
style: STextStyles.label(context).copyWith(
fontSize: 12,
),
),
SizedBox(
height: isDesktop ? 24 : 4,
), ),
Text( Text(
"Recovery Phrase", "Recovery Phrase",
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: STextStyles.pageTitleH1, style: isDesktop
? STextStyles.desktopH2(context)
: STextStyles.pageTitleH1(context),
), ),
const SizedBox( const SizedBox(
height: 16, height: 16,
), ),
Container( Container(
decoration: BoxDecoration( decoration: BoxDecoration(
color: CFColors.white, color: isDesktop
? Theme.of(context).extension<StackColors>()!.background
: Theme.of(context).extension<StackColors>()!.popupBG,
borderRadius: BorderRadius.circular( borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius), Constants.size.circularBorderRadius),
), ),
child: Padding( child: Padding(
padding: const EdgeInsets.all(12), padding: isDesktop
? const EdgeInsets.all(0)
: const EdgeInsets.all(12),
child: Text( child: Text(
"Please write down your recovery phrase in the correct order and save it to keep your funds secure. You will also be asked to verify the words on the next screen.", "Please write down your recovery phrase in the correct order and save it to keep your funds secure. You will also be asked to verify the words on the next screen.",
style: STextStyles.label.copyWith( textAlign: TextAlign.center,
color: CFColors.stackAccent, style: isDesktop
), ? STextStyles.desktopSubtitleH2(context)
: STextStyles.label(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.accentColorDark),
), ),
), ),
), ),
const SizedBox( SizedBox(
height: 8, height: isDesktop ? 21 : 8,
), ),
Expanded( if (!isDesktop)
child: SingleChildScrollView( Expanded(
child: MnemonicTable( child: SingleChildScrollView(
words: _mnemonic, child: MnemonicTable(
words: _mnemonic,
isDesktop: isDesktop,
),
),
),
if (isDesktop)
MnemonicTable(
words: _mnemonic,
isDesktop: isDesktop,
),
SizedBox(
height: isDesktop ? 24 : 16,
),
if (isDesktop)
SizedBox(
height: 70,
child: TextButton(
onPressed: () async {
await _copy();
},
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SvgPicture.asset(
Assets.svg.copy,
width: 20,
height: 20,
color: Theme.of(context)
.extension<StackColors>()!
.buttonTextSecondary,
),
const SizedBox(
width: 10,
),
Text(
"Copy to clipboard",
style: STextStyles.desktopButtonSecondaryEnabled(
context),
)
],
),
),
),
if (isDesktop)
const SizedBox(
height: 16,
),
ConstrainedBox(
constraints: BoxConstraints(
minHeight: isDesktop ? 70 : 0,
),
child: TextButton(
onPressed: () async {
final int next = Random().nextInt(_mnemonic.length);
ref
.read(verifyMnemonicWordIndexStateProvider.state)
.update((state) => next);
ref
.read(verifyMnemonicCorrectWordStateProvider.state)
.update((state) => _mnemonic[next]);
unawaited(Navigator.of(context).pushNamed(
VerifyRecoveryPhraseView.routeName,
arguments: Tuple2(_manager, _mnemonic),
));
},
style: Theme.of(context)
.extension<StackColors>()!
.getPrimaryEnabledButtonColor(context),
child: Text(
"I saved my recovery phrase",
style: isDesktop
? STextStyles.desktopButtonEnabled(context)
: STextStyles.button(context),
), ),
), ),
), ),
const SizedBox( if (isDesktop)
height: 16, const Spacer(
), flex: 15,
TextButton(
onPressed: () async {
final int next = Random().nextInt(_mnemonic.length);
ref
.read(verifyMnemonicWordIndexStateProvider.state)
.update((state) => next);
ref
.read(verifyMnemonicCorrectWordStateProvider.state)
.update((state) => _mnemonic[next]);
Navigator.of(context).pushNamed(
VerifyRecoveryPhraseView.routeName,
arguments: Tuple2(_manager, _mnemonic),
);
},
style: Theme.of(context).textButtonTheme.style?.copyWith(
backgroundColor: MaterialStateProperty.all<Color>(
CFColors.stackAccent,
),
),
child: Text(
"I saved my recovery phrase",
style: STextStyles.button,
), ),
),
], ],
), ),
), ),

View file

@ -1,19 +1,20 @@
import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart';
import 'package:stackwallet/pages/add_wallet_views/new_wallet_recovery_phrase_view/sub_widgets/mnemonic_table_item.dart'; import 'package:stackwallet/pages/add_wallet_views/new_wallet_recovery_phrase_view/sub_widgets/mnemonic_table_item.dart';
class MnemonicTable extends StatelessWidget { class MnemonicTable extends StatelessWidget {
const MnemonicTable({ const MnemonicTable({
Key? key, Key? key,
required this.words, required this.words,
required this.isDesktop,
}) : super(key: key); }) : super(key: key);
final List<String> words; final List<String> words;
final bool isDesktop;
static const wordsPerRow = 3;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
debugPrint("BUILD: $runtimeType"); debugPrint("BUILD: $runtimeType");
final wordsPerRow = isDesktop ? 4 : 3;
final int rows = words.length ~/ wordsPerRow; final int rows = words.length ~/ wordsPerRow;
@ -26,51 +27,54 @@ class MnemonicTable extends StatelessWidget {
children: [ children: [
for (int i = 1; i <= rows; i++) for (int i = 1; i <= rows; i++)
Padding( Padding(
padding: const EdgeInsets.symmetric(vertical: 5), padding: EdgeInsets.symmetric(vertical: isDesktop ? 8 : 5),
child: Row( child: Row(
children: [ children: [
for (int j = 1; j <= wordsPerRow; j++) ...[ for (int j = 1; j <= wordsPerRow; j++) ...[
if (j > 1) if (j > 1)
const SizedBox( SizedBox(
width: 6, width: isDesktop ? 10 : 6,
), ),
Expanded( Expanded(
child: MnemonicTableItem( child: MnemonicTableItem(
number: ++index, number: ++index,
word: words[index - 1], word: words[index - 1],
isDesktop: isDesktop,
), ),
), ),
], ],
], ],
), ),
), ),
Padding( if (index != words.length)
padding: const EdgeInsets.symmetric(vertical: 5), Padding(
child: Row( padding: EdgeInsets.symmetric(vertical: isDesktop ? 8 : 5),
children: [ child: Row(
for (int i = index; i < words.length; i++) ...[ children: [
if (i > index) for (int i = index; i < words.length; i++) ...[
if (i > index)
SizedBox(
width: isDesktop ? 10 : 6,
),
Expanded(
child: MnemonicTableItem(
number: i + 1,
word: words[i],
isDesktop: isDesktop,
),
),
],
for (int i = remainder; i < wordsPerRow; i++) ...[
const SizedBox( const SizedBox(
width: 6, width: 6,
), ),
Expanded( Expanded(
child: MnemonicTableItem( child: Container(),
number: i + 1,
word: words[i],
), ),
), ],
], ],
for (int i = remainder; i < wordsPerRow; i++) ...[ ),
const SizedBox(
width: 6,
),
Expanded(
child: Container(),
),
],
],
), ),
),
], ],
); );
} }

View file

@ -1,49 +1,57 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:stackwallet/utilities/cfcolors.dart';
import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/widgets/rounded_white_container.dart';
class MnemonicTableItem extends StatelessWidget { class MnemonicTableItem extends StatelessWidget {
const MnemonicTableItem({ const MnemonicTableItem({
Key? key, Key? key,
required this.number, required this.number,
required this.word, required this.word,
required this.isDesktop,
}) : super(key: key); }) : super(key: key);
final int number; final int number;
final String word; final String word;
final bool isDesktop;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
debugPrint("BUILD: $runtimeType"); debugPrint("BUILD: $runtimeType");
return Container( return RoundedWhiteContainer(
decoration: BoxDecoration( padding: isDesktop
color: CFColors.white, ? const EdgeInsets.symmetric(horizontal: 12, vertical: 9)
borderRadius: BorderRadius.circular( : const EdgeInsets.all(8),
Constants.size.circularBorderRadius, child: Row(
), mainAxisAlignment: MainAxisAlignment.start,
), children: [
child: Padding( Text(
padding: const EdgeInsets.all(8), number.toString(),
child: Row( style: isDesktop
mainAxisAlignment: MainAxisAlignment.start, ? STextStyles.desktopTextExtraSmall(context).copyWith(
children: [ color: Theme.of(context)
Text( .extension<StackColors>()!
number.toString(), .textSubtitle2,
style: STextStyles.baseXS.copyWith( )
color: CFColors.gray3, : STextStyles.baseXS(context).copyWith(
fontSize: 10, color: Theme.of(context)
), .extension<StackColors>()!
), .textSubtitle2,
const SizedBox( fontSize: 10,
width: 8, ),
), ),
Text( const SizedBox(
word, width: 8,
style: STextStyles.baseXS, ),
), Text(
], word,
), style: isDesktop
? STextStyles.desktopTextExtraSmall(context).copyWith(
color: Theme.of(context).extension<StackColors>()!.textDark,
)
: STextStyles.baseXS(context),
),
],
), ),
); );
} }

View file

@ -1,18 +1,25 @@
import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:stackwallet/pages/add_wallet_views/new_wallet_recovery_phrase_view/new_wallet_recovery_phrase_view.dart'; import 'package:stackwallet/pages/add_wallet_views/new_wallet_recovery_phrase_view/new_wallet_recovery_phrase_view.dart';
import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/exit_to_my_stack_button.dart';
import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/providers/providers.dart';
import 'package:stackwallet/services/coins/coin_service.dart'; import 'package:stackwallet/services/coins/coin_service.dart';
import 'package:stackwallet/services/coins/manager.dart'; import 'package:stackwallet/services/coins/manager.dart';
import 'package:stackwallet/services/transaction_notification_tracker.dart'; import 'package:stackwallet/services/transaction_notification_tracker.dart';
import 'package:stackwallet/utilities/cfcolors.dart';
import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/default_nodes.dart'; import 'package:stackwallet/utilities/default_nodes.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart';
import 'package:stackwallet/utilities/logger.dart'; import 'package:stackwallet/utilities/logger.dart';
import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/utilities/util.dart';
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart';
import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
import 'package:stackwallet/widgets/loading_indicator.dart'; import 'package:stackwallet/widgets/loading_indicator.dart';
import 'package:stackwallet/widgets/rounded_white_container.dart';
import 'package:tuple/tuple.dart'; import 'package:tuple/tuple.dart';
class NewWalletRecoveryPhraseWarningView extends StatefulWidget { class NewWalletRecoveryPhraseWarningView extends StatefulWidget {
@ -36,11 +43,13 @@ class _NewWalletRecoveryPhraseWarningViewState
extends State<NewWalletRecoveryPhraseWarningView> { extends State<NewWalletRecoveryPhraseWarningView> {
late final Coin coin; late final Coin coin;
late final String walletName; late final String walletName;
late final bool isDesktop;
@override @override
void initState() { void initState() {
coin = widget.coin; coin = widget.coin;
walletName = widget.walletName; walletName = widget.walletName;
isDesktop = Util.isDesktop;
super.initState(); super.initState();
} }
@ -52,63 +61,82 @@ class _NewWalletRecoveryPhraseWarningViewState
? Constants.seedPhraseWordCountMonero ? Constants.seedPhraseWordCountMonero
: Constants.seedPhraseWordCountBip39; : Constants.seedPhraseWordCountBip39;
return Scaffold( return MasterScaffold(
appBar: AppBar( isDesktop: isDesktop,
leading: AppBarBackButton( appBar: isDesktop
onPressed: () { ? const DesktopAppBar(
Navigator.of(context).pop(); isCompactHeight: false,
}, leading: AppBarBackButton(),
), trailing: ExitToMyStackButton(),
), )
body: Container( : AppBar(
color: CFColors.almostWhite, leading: const AppBarBackButton(),
child: Padding( ),
padding: const EdgeInsets.all(16), body: Padding(
child: Column( padding: EdgeInsets.all(isDesktop ? 0 : 16),
crossAxisAlignment: CrossAxisAlignment.stretch, child: Column(
children: [ crossAxisAlignment: isDesktop
? CrossAxisAlignment.center
: CrossAxisAlignment.stretch,
children: [
if (isDesktop)
const Spacer(
flex: 10,
),
if (!isDesktop)
const SizedBox( const SizedBox(
height: 4, height: 4,
), ),
if (!isDesktop)
Text( Text(
walletName, walletName,
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: STextStyles.label.copyWith( style: STextStyles.label(context).copyWith(
fontSize: 12, fontSize: 12,
), ),
), ),
if (!isDesktop)
const SizedBox( const SizedBox(
height: 4, height: 4,
), ),
Text( Text(
"Recovery Phrase", "Recovery Phrase",
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: STextStyles.pageTitleH1, style: isDesktop
? STextStyles.desktopH2(context)
: STextStyles.pageTitleH1(context),
),
SizedBox(
height: isDesktop ? 32 : 16,
),
RoundedWhiteContainer(
padding: isDesktop
? const EdgeInsets.all(32)
: const EdgeInsets.all(12),
width: isDesktop ? 480 : null,
child: Text(
"On the next screen you will see $_numberOfPhraseWords words that make up your recovery phrase.\n\nPlease write it down. Keep it safe and never share it with anyone. Your recovery phrase is the only way you can access your funds if you forget your PIN, lose your phone, etc.\n\nStack Wallet does not keep nor is able to restore your recover phrase. Only you have access to your wallet.",
style: isDesktop
? STextStyles.desktopTextMediumRegular(context)
: STextStyles.subtitle(context).copyWith(
fontSize: 12,
),
), ),
),
if (!isDesktop) const Spacer(),
if (isDesktop)
const SizedBox( const SizedBox(
height: 16, height: 32,
), ),
Container( ConstrainedBox(
decoration: BoxDecoration( constraints: BoxConstraints(
color: CFColors.white, maxWidth: isDesktop ? 480 : 0,
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius),
),
child: Padding(
padding: const EdgeInsets.all(12),
child: Text(
"On the next screen you will see $_numberOfPhraseWords words that make up your recovery phrase.\n\nPlease write it down. Keep it safe and never share it with anyone. Your recovery phrase is the only way you can access your funds if you forget your PIN, lose your phone, etc.\n\nStack Wallet does not keep nor is able to restore your recover phrase. Only you have access to your wallet.",
style: STextStyles.subtitle.copyWith(
fontSize: 12,
),
),
),
), ),
const Spacer(), child: Consumer(
Consumer(
builder: (_, ref, __) { builder: (_, ref, __) {
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisSize: MainAxisSize.min,
children: [ children: [
GestureDetector( GestureDetector(
onTap: () { onTap: () {
@ -119,6 +147,9 @@ class _NewWalletRecoveryPhraseWarningViewState
child: Container( child: Container(
color: Colors.transparent, color: Colors.transparent,
child: Row( child: Row(
crossAxisAlignment: isDesktop
? CrossAxisAlignment.start
: CrossAxisAlignment.center,
children: [ children: [
Checkbox( Checkbox(
materialTapTargetSize: materialTapTargetSize:
@ -131,138 +162,147 @@ class _NewWalletRecoveryPhraseWarningViewState
newValue!; newValue!;
}, },
), ),
const SizedBox( SizedBox(
width: 4, width: isDesktop ? 14 : 4,
), ),
Flexible( Flexible(
child: Text( child: Text(
"I understand that if I lose my recovery phrase, I will not be able to access my funds.", "I understand that if I lose my recovery phrase, I will not be able to access my funds.",
style: STextStyles.baseXS, style: isDesktop
? STextStyles.desktopTextMedium(context)
: STextStyles.baseXS(context),
), ),
), ),
], ],
), ),
), ),
), ),
const SizedBox( SizedBox(
height: 16, height: isDesktop ? 32 : 16,
), ),
TextButton( ConstrainedBox(
onPressed: ref.read(checkBoxStateProvider.state).state constraints: BoxConstraints(
? () async { minHeight: isDesktop ? 70 : 0,
try { ),
showDialog<dynamic>( child: TextButton(
context: context, onPressed: ref.read(checkBoxStateProvider.state).state
barrierDismissible: false, ? () async {
useSafeArea: true, try {
builder: (ctx) { unawaited(showDialog<dynamic>(
return const Center( context: context,
child: LoadingIndicator( barrierDismissible: false,
width: 50, useSafeArea: true,
height: 50, builder: (ctx) {
), return const Center(
); child: LoadingIndicator(
}, width: 50,
); height: 50,
),
final walletsService = ref.read(
walletsServiceChangeNotifierProvider);
final walletId =
await walletsService.addNewWallet(
name: walletName,
coin: coin,
shouldNotifyListeners: false,
);
var node = ref
.read(nodeServiceChangeNotifierProvider)
.getPrimaryNodeFor(coin: coin);
if (node == null) {
node = DefaultNodes.getNodeFor(coin);
ref
.read(nodeServiceChangeNotifierProvider)
.setPrimaryNodeFor(
coin: coin,
node: node,
); );
} },
));
final txTracker = final walletsService = ref.read(
TransactionNotificationTracker( walletsServiceChangeNotifierProvider);
walletId: walletId!);
final failovers = ref final walletId =
.read(nodeServiceChangeNotifierProvider) await walletsService.addNewWallet(
.failoverNodesFor(coin: widget.coin); name: walletName,
coin: coin,
final wallet = CoinServiceAPI.from( shouldNotifyListeners: false,
coin,
walletId,
walletName,
node,
txTracker,
ref.read(prefsChangeNotifierProvider),
failovers,
);
final manager = Manager(wallet);
await manager.initializeNew();
// pop progress dialog
if (mounted) {
Navigator.pop(context);
}
// set checkbox back to unchecked to annoy users to agree again :P
ref.read(checkBoxStateProvider.state).state =
false;
if (mounted) {
Navigator.of(context).pushNamed(
NewWalletRecoveryPhraseView.routeName,
arguments: Tuple2(
manager,
await manager.mnemonic,
),
); );
var node = ref
.read(nodeServiceChangeNotifierProvider)
.getPrimaryNodeFor(coin: coin);
if (node == null) {
node = DefaultNodes.getNodeFor(coin);
await ref
.read(
nodeServiceChangeNotifierProvider)
.setPrimaryNodeFor(
coin: coin,
node: node,
);
}
final txTracker =
TransactionNotificationTracker(
walletId: walletId!);
final failovers = ref
.read(nodeServiceChangeNotifierProvider)
.failoverNodesFor(coin: widget.coin);
final wallet = CoinServiceAPI.from(
coin,
walletId,
walletName,
node,
txTracker,
ref.read(prefsChangeNotifierProvider),
failovers,
);
final manager = Manager(wallet);
await manager.initializeNew();
// pop progress dialog
if (mounted) {
Navigator.pop(context);
}
// set checkbox back to unchecked to annoy users to agree again :P
ref
.read(checkBoxStateProvider.state)
.state = false;
if (mounted) {
unawaited(Navigator.of(context).pushNamed(
NewWalletRecoveryPhraseView.routeName,
arguments: Tuple2(
manager,
await manager.mnemonic,
),
));
}
} catch (e, s) {
Logging.instance
.log("$e\n$s", level: LogLevel.Fatal);
// TODO: handle gracefully
// any network/socket exception here will break new wallet creation
rethrow;
} }
} catch (e, s) {
Logging.instance
.log("$e\n$s", level: LogLevel.Fatal);
// TODO: handle gracefully
// any network/socket exception here will break new wallet creation
rethrow;
} }
} : null,
: null, style: ref.read(checkBoxStateProvider.state).state
style: ref.read(checkBoxStateProvider.state).state ? Theme.of(context)
? Theme.of(context).textButtonTheme.style?.copyWith( .extension<StackColors>()!
backgroundColor: .getPrimaryEnabledButtonColor(context)
MaterialStateProperty.all<Color>( : Theme.of(context)
CFColors.stackAccent, .extension<StackColors>()!
), .getPrimaryDisabledButtonColor(context),
) child: Text(
: Theme.of(context).textButtonTheme.style?.copyWith( "View recovery phrase",
backgroundColor: style: isDesktop
MaterialStateProperty.all<Color>( ? ref.read(checkBoxStateProvider.state).state
CFColors.stackAccent.withOpacity( ? STextStyles.desktopButtonEnabled(context)
0.25, : STextStyles.desktopButtonDisabled(context)
), : STextStyles.button(context),
), ),
),
child: Text(
"View recovery phrase",
style: STextStyles.button,
), ),
), ),
], ],
); );
}, },
), ),
], ),
), if (isDesktop)
const Spacer(
flex: 15,
),
],
), ),
), ),
); );

View file

@ -1,6 +1,13 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:stackwallet/utilities/cfcolors.dart'; import 'package:flutter_svg/svg.dart';
import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/utilities/util.dart';
import 'package:stackwallet/widgets/desktop/desktop_dialog.dart';
import 'package:stackwallet/widgets/desktop/desktop_dialog_close_button.dart';
import 'package:stackwallet/widgets/desktop/primary_button.dart';
import 'package:stackwallet/widgets/desktop/secondary_button.dart';
import 'package:stackwallet/widgets/stack_dialog.dart'; import 'package:stackwallet/widgets/stack_dialog.dart';
class ConfirmRecoveryDialog extends StatelessWidget { class ConfirmRecoveryDialog extends StatelessWidget {
@ -11,44 +18,94 @@ class ConfirmRecoveryDialog extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return WillPopScope( if (Util.isDesktop) {
onWillPop: () async { return DesktopDialog(
return true; child: Column(
}, children: [
child: StackDialog( const DesktopDialogCloseButton(),
title: "Are you ready?", const SizedBox(
message: height: 5,
"Restoring your wallet may take a while. Please do not exit this screen once the process is started.", ),
leftButton: TextButton( SvgPicture.asset(
style: Theme.of(context).textButtonTheme.style?.copyWith( Assets.svg.drd,
backgroundColor: MaterialStateProperty.all<Color>( width: 99,
CFColors.buttonGray, height: 70,
), ),
const Spacer(),
Text(
"Restore wallet",
style: STextStyles.desktopH2(context),
textAlign: TextAlign.center,
),
const SizedBox(
height: 16,
),
Text(
"Restoring your wallet may take a while.\nPlease do not exit this screen once the process is started.",
style: STextStyles.desktopTextMedium(context).copyWith(
color: Theme.of(context).extension<StackColors>()!.textDark3,
), ),
child: Text( textAlign: TextAlign.center,
"Cancel", ),
style: STextStyles.itemSubtitle12, const Spacer(),
), Padding(
onPressed: () { padding: const EdgeInsets.only(
Navigator.of(context).pop(); left: 32,
}, right: 32,
), bottom: 32,
rightButton: TextButton(
style: Theme.of(context).textButtonTheme.style?.copyWith(
backgroundColor: MaterialStateProperty.all<Color>(
CFColors.stackAccent,
),
), ),
child: Text( child: Row(
"Restore", children: [
style: STextStyles.button, Expanded(
), child: SecondaryButton(
onPressed: () { label: "Cancel",
Navigator.of(context).pop(); onPressed: () {
onConfirm.call(); Navigator.of(context).pop();
}, },
),
),
const SizedBox(
width: 16,
),
Expanded(
child: PrimaryButton(
label: "Restore",
onPressed: () {
Navigator.of(context).pop();
onConfirm.call();
},
),
)
],
),
)
],
), ),
), );
); } else {
return WillPopScope(
onWillPop: () async {
return true;
},
child: StackDialog(
title: "Are you ready?",
message:
"Restoring your wallet may take a while. Please do not exit this screen once the process is started.",
leftButton: SecondaryButton(
label: "Cancel",
onPressed: () {
Navigator.of(context).pop();
},
),
rightButton: PrimaryButton(
label: "Restore",
onPressed: () {
Navigator.of(context).pop();
onConfirm.call();
},
),
),
);
}
} }
} }

View file

@ -1,409 +0,0 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_rounded_date_picker/flutter_rounded_date_picker.dart';
import 'package:flutter_svg/svg.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:stackwallet/pages/add_wallet_views/restore_wallet_view/restore_wallet_view.dart';
import 'package:stackwallet/pages/add_wallet_views/restore_wallet_view/sub_widgets/mnemonic_word_count_select_sheet.dart';
import 'package:stackwallet/providers/ui/verify_recovery_phrase/mnemonic_word_count_state_provider.dart';
import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/cfcolors.dart';
import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart';
import 'package:stackwallet/utilities/format.dart';
import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
import 'package:stackwallet/widgets/rounded_white_container.dart';
import 'package:tuple/tuple.dart';
class RestoreOptionsView extends ConsumerStatefulWidget {
const RestoreOptionsView({
Key? key,
required this.walletName,
required this.coin,
}) : super(key: key);
static const routeName = "/restoreOptions";
final String walletName;
final Coin coin;
@override
ConsumerState<RestoreOptionsView> createState() => _RestoreOptionsViewState();
}
class _RestoreOptionsViewState extends ConsumerState<RestoreOptionsView> {
late final String walletName;
late final Coin coin;
late TextEditingController _dateController;
late TextEditingController _lengthController;
late FocusNode textFieldFocusNode;
final bool _nextEnabled = true;
DateTime _restoreFromDate = DateTime.fromMillisecondsSinceEpoch(0);
@override
void initState() {
walletName = widget.walletName;
coin = widget.coin;
_dateController = TextEditingController();
_lengthController = TextEditingController();
textFieldFocusNode = FocusNode();
super.initState();
}
@override
void dispose() {
_dateController.dispose();
_lengthController.dispose();
textFieldFocusNode.dispose();
super.dispose();
}
final _datePickerTextStyleBase = GoogleFonts.inter(
color: CFColors.gray3,
fontSize: 12,
fontWeight: FontWeight.w400,
letterSpacing: 0.5,
);
MaterialRoundedDatePickerStyle _buildDatePickerStyle() {
return MaterialRoundedDatePickerStyle(
paddingMonthHeader: const EdgeInsets.only(top: 11),
colorArrowNext: CFColors.neutral60,
colorArrowPrevious: CFColors.neutral60,
textStyleButtonNegative: _datePickerTextStyleBase.copyWith(
fontSize: 16, fontWeight: FontWeight.w600),
textStyleButtonPositive: _datePickerTextStyleBase.copyWith(
fontSize: 16, fontWeight: FontWeight.w600),
textStyleCurrentDayOnCalendar: _datePickerTextStyleBase.copyWith(
color: CFColors.stackAccent,
),
textStyleDayHeader: _datePickerTextStyleBase.copyWith(
color: CFColors.stackAccent,
fontSize: 16,
fontWeight: FontWeight.w600,
),
textStyleDayOnCalendar: _datePickerTextStyleBase,
textStyleDayOnCalendarDisabled: _datePickerTextStyleBase.copyWith(
color: CFColors.neutral80,
),
textStyleDayOnCalendarSelected: _datePickerTextStyleBase.copyWith(
color: CFColors.white,
),
textStyleMonthYearHeader: _datePickerTextStyleBase.copyWith(
color: CFColors.neutral60,
fontSize: 16,
fontWeight: FontWeight.w600,
),
textStyleYearButton: _datePickerTextStyleBase.copyWith(
color: CFColors.white,
fontSize: 16,
fontWeight: FontWeight.w600,
),
textStyleButtonAction: GoogleFonts.inter(),
);
}
MaterialRoundedYearPickerStyle _buildYearPickerStyle() {
return MaterialRoundedYearPickerStyle(
textStyleYear: _datePickerTextStyleBase.copyWith(
color: CFColors.gray3,
fontWeight: FontWeight.w600,
fontSize: 16,
),
textStyleYearSelected: _datePickerTextStyleBase.copyWith(
color: CFColors.stackAccent,
fontWeight: FontWeight.w600,
fontSize: 18,
),
);
}
@override
Widget build(BuildContext context) {
debugPrint("BUILD: $runtimeType with ${coin.name} $walletName");
return Scaffold(
appBar: AppBar(
leading: AppBarBackButton(
onPressed: () {
if (textFieldFocusNode.hasFocus) {
textFieldFocusNode.unfocus();
Future<void>.delayed(const Duration(milliseconds: 100))
.then((value) => Navigator.of(context).pop());
} else {
Navigator.of(context).pop();
}
},
),
),
body: Container(
color: CFColors.almostWhite,
child: Padding(
padding: const EdgeInsets.all(16),
child: LayoutBuilder(
builder: (ctx, constraints) {
return SingleChildScrollView(
child: ConstrainedBox(
constraints: BoxConstraints(minHeight: constraints.maxHeight),
child: IntrinsicHeight(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const Spacer(
flex: 1,
),
Image(
image: AssetImage(
Assets.png.imageFor(coin: coin),
),
height: 100,
),
const SizedBox(
height: 16,
),
Text(
"Restore options",
textAlign: TextAlign.center,
style: STextStyles.pageTitleH1,
),
const SizedBox(
height: 24,
),
if (coin == Coin.monero || coin == Coin.epicCash)
Text(
"Choose start date",
style: STextStyles.smallMed12,
textAlign: TextAlign.left,
),
if (coin == Coin.monero || coin == Coin.epicCash)
const SizedBox(
height: 8,
),
if (coin == Coin.monero || coin == Coin.epicCash)
Container(
color: Colors.transparent,
child: TextField(
onTap: () async {
final height =
MediaQuery.of(context).size.height;
// check and hide keyboard
if (FocusScope.of(context).hasFocus) {
FocusScope.of(context).unfocus();
await Future<void>.delayed(
const Duration(milliseconds: 125));
}
final date = await showRoundedDatePicker(
context: context,
initialDate: DateTime.now(),
height: height * 0.5,
theme: ThemeData(
primarySwatch: CFColors.createMaterialColor(
CFColors.stackAccent),
),
//TODO pick a better initial date
// 2007 chosen as that is just before bitcoin launched
firstDate: DateTime(2007),
lastDate: DateTime.now(),
borderRadius:
Constants.size.circularBorderRadius * 2,
textPositiveButton: "SELECT",
styleDatePicker: _buildDatePickerStyle(),
styleYearPicker: _buildYearPickerStyle(),
);
if (date != null) {
_restoreFromDate = date;
_dateController.text =
Format.formatDate(date);
}
},
controller: _dateController,
style: STextStyles.field,
decoration: InputDecoration(
hintText: "Restore from...",
suffixIcon: UnconstrainedBox(
child: Row(
children: [
const SizedBox(
width: 16,
),
SvgPicture.asset(
Assets.svg.calendar,
color: CFColors.neutral50,
width: 16,
height: 16,
),
const SizedBox(
width: 12,
),
],
),
),
),
key: const Key("restoreOptionsViewDatePickerKey"),
readOnly: true,
toolbarOptions: const ToolbarOptions(
copy: true,
cut: false,
paste: false,
selectAll: false,
),
onChanged: (newValue) {},
),
),
if (coin == Coin.monero || coin == Coin.epicCash)
const SizedBox(
height: 8,
),
if (coin == Coin.monero || coin == Coin.epicCash)
RoundedWhiteContainer(
child: Center(
child: Text(
"Choose the date you made the wallet (approximate is fine)",
style: STextStyles.smallMed12.copyWith(
fontSize: 10,
),
),
),
),
if (coin == Coin.monero || coin == Coin.epicCash)
const SizedBox(
height: 16,
),
Text(
"Choose recovery phrase length",
style: STextStyles.smallMed12,
textAlign: TextAlign.left,
),
const SizedBox(
height: 8,
),
Stack(
children: [
TextField(
controller: _lengthController,
readOnly: true,
textInputAction: TextInputAction.none,
),
Padding(
padding: const EdgeInsets.symmetric(
horizontal: 12,
),
child: RawMaterialButton(
splashColor: CFColors.splashLight,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
),
),
onPressed: () {
showModalBottomSheet<dynamic>(
backgroundColor: Colors.transparent,
context: context,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(
top: Radius.circular(20),
),
),
builder: (_) {
return MnemonicWordCountSelectSheet(
lengthOptions:
Constants.possibleLengthsForCoin(
coin),
);
},
);
},
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Text(
"${ref.watch(mnemonicWordCountStateProvider.state).state} words",
style: STextStyles.itemSubtitle12,
),
SvgPicture.asset(
Assets.svg.chevronDown,
width: 8,
height: 4,
color: CFColors.gray3,
),
],
),
),
)
],
),
const Spacer(
flex: 3,
),
TextButton(
onPressed: _nextEnabled
? () async {
// hide keyboard if has focus
if (FocusScope.of(context).hasFocus) {
FocusScope.of(context).unfocus();
await Future<void>.delayed(
const Duration(milliseconds: 75));
}
if (mounted) {
Navigator.of(context).pushNamed(
RestoreWalletView.routeName,
arguments: Tuple4(
walletName,
coin,
ref
.read(mnemonicWordCountStateProvider
.state)
.state,
_restoreFromDate,
),
);
}
}
: null,
style: _nextEnabled
? Theme.of(context)
.textButtonTheme
.style
?.copyWith(
backgroundColor:
MaterialStateProperty.all<Color>(
CFColors.stackAccent,
),
)
: Theme.of(context)
.textButtonTheme
.style
?.copyWith(
backgroundColor:
MaterialStateProperty.all<Color>(
CFColors.stackAccent.withOpacity(
0.25,
),
),
),
child: Text(
"Next",
style: STextStyles.button,
),
),
],
),
),
),
);
},
),
),
),
);
}
}

View file

@ -0,0 +1,398 @@
import 'package:dropdown_button2/dropdown_button2.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_rounded_date_picker/flutter_rounded_date_picker.dart';
import 'package:flutter_svg/svg.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:stackwallet/pages/add_wallet_views/restore_wallet_view/restore_options_view/sub_widgets/mobile_mnemonic_length_selector.dart';
import 'package:stackwallet/pages/add_wallet_views/restore_wallet_view/restore_options_view/sub_widgets/restore_from_date_picker.dart';
import 'package:stackwallet/pages/add_wallet_views/restore_wallet_view/restore_options_view/sub_widgets/restore_options_next_button.dart';
import 'package:stackwallet/pages/add_wallet_views/restore_wallet_view/restore_options_view/sub_widgets/restore_options_platform_layout.dart';
import 'package:stackwallet/pages/add_wallet_views/restore_wallet_view/restore_wallet_view.dart';
import 'package:stackwallet/pages/add_wallet_views/restore_wallet_view/sub_widgets/mnemonic_word_count_select_sheet.dart';
import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/exit_to_my_stack_button.dart';
import 'package:stackwallet/providers/ui/color_theme_provider.dart';
import 'package:stackwallet/providers/ui/verify_recovery_phrase/mnemonic_word_count_state_provider.dart';
import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart';
import 'package:stackwallet/utilities/format.dart';
import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/utilities/util.dart';
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart';
import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
import 'package:stackwallet/widgets/rounded_white_container.dart';
import 'package:tuple/tuple.dart';
class RestoreOptionsView extends ConsumerStatefulWidget {
const RestoreOptionsView({
Key? key,
required this.walletName,
required this.coin,
}) : super(key: key);
static const routeName = "/restoreOptions";
final String walletName;
final Coin coin;
@override
ConsumerState<RestoreOptionsView> createState() => _RestoreOptionsViewState();
}
class _RestoreOptionsViewState extends ConsumerState<RestoreOptionsView> {
late final String walletName;
late final Coin coin;
late final bool isDesktop;
late TextEditingController _dateController;
late FocusNode textFieldFocusNode;
final bool _nextEnabled = true;
DateTime _restoreFromDate = DateTime.fromMillisecondsSinceEpoch(0);
late final Color baseColor;
@override
void initState() {
baseColor = ref.read(colorThemeProvider.state).state.textSubtitle2;
walletName = widget.walletName;
coin = widget.coin;
isDesktop = Util.isDesktop;
_dateController = TextEditingController();
textFieldFocusNode = FocusNode();
super.initState();
}
@override
void dispose() {
_dateController.dispose();
textFieldFocusNode.dispose();
super.dispose();
}
MaterialRoundedDatePickerStyle _buildDatePickerStyle() {
return MaterialRoundedDatePickerStyle(
paddingMonthHeader: const EdgeInsets.only(top: 11),
colorArrowNext: Theme.of(context).extension<StackColors>()!.textSubtitle1,
colorArrowPrevious:
Theme.of(context).extension<StackColors>()!.textSubtitle1,
textStyleButtonNegative: STextStyles.datePicker600(context).copyWith(
color: baseColor,
),
textStyleButtonPositive: STextStyles.datePicker600(context).copyWith(
color: baseColor,
),
textStyleCurrentDayOnCalendar: STextStyles.datePicker400(context),
textStyleDayHeader: STextStyles.datePicker600(context),
textStyleDayOnCalendar: STextStyles.datePicker400(context).copyWith(
color: baseColor,
),
textStyleDayOnCalendarDisabled:
STextStyles.datePicker400(context).copyWith(
color: Theme.of(context).extension<StackColors>()!.textSubtitle3,
),
textStyleDayOnCalendarSelected:
STextStyles.datePicker400(context).copyWith(
color: Theme.of(context).extension<StackColors>()!.popupBG,
),
textStyleMonthYearHeader: STextStyles.datePicker600(context).copyWith(
color: Theme.of(context).extension<StackColors>()!.textSubtitle1,
),
textStyleYearButton: STextStyles.datePicker600(context).copyWith(
color: Theme.of(context).extension<StackColors>()!.textWhite,
),
textStyleButtonAction: GoogleFonts.inter(),
);
}
MaterialRoundedYearPickerStyle _buildYearPickerStyle() {
return MaterialRoundedYearPickerStyle(
textStyleYear: STextStyles.datePicker600(context).copyWith(
color: Theme.of(context).extension<StackColors>()!.textSubtitle2,
),
textStyleYearSelected: STextStyles.datePicker600(context).copyWith(
fontSize: 18,
),
);
}
Future<void> nextPressed() async {
if (!isDesktop) {
// hide keyboard if has focus
if (FocusScope.of(context).hasFocus) {
FocusScope.of(context).unfocus();
await Future<void>.delayed(const Duration(milliseconds: 75));
}
}
if (mounted) {
await Navigator.of(context).pushNamed(
RestoreWalletView.routeName,
arguments: Tuple4(
walletName,
coin,
ref.read(mnemonicWordCountStateProvider.state).state,
_restoreFromDate,
),
);
}
}
Future<void> chooseDate() async {
final height = MediaQuery.of(context).size.height;
// check and hide keyboard
if (FocusScope.of(context).hasFocus) {
FocusScope.of(context).unfocus();
await Future<void>.delayed(const Duration(milliseconds: 125));
}
final date = await showRoundedDatePicker(
context: context,
initialDate: DateTime.now(),
height: height * 0.5,
theme: ThemeData(
primarySwatch: Util.createMaterialColor(
Theme.of(context).extension<StackColors>()!.accentColorDark),
),
//TODO pick a better initial date
// 2007 chosen as that is just before bitcoin launched
firstDate: DateTime(2007),
lastDate: DateTime.now(),
borderRadius: Constants.size.circularBorderRadius * 2,
textPositiveButton: "SELECT",
styleDatePicker: _buildDatePickerStyle(),
styleYearPicker: _buildYearPickerStyle(),
);
if (date != null) {
_restoreFromDate = date;
_dateController.text = Format.formatDate(date);
}
}
Future<void> chooseMnemonicLength() async {
await showModalBottomSheet<dynamic>(
backgroundColor: Colors.transparent,
context: context,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(
top: Radius.circular(20),
),
),
builder: (_) {
return MnemonicWordCountSelectSheet(
lengthOptions: Constants.possibleLengthsForCoin(coin),
);
},
);
}
@override
Widget build(BuildContext context) {
debugPrint("BUILD: $runtimeType with ${coin.name} $walletName");
final lengths = Constants.possibleLengthsForCoin(coin).toList();
return MasterScaffold(
isDesktop: isDesktop,
appBar: isDesktop
? const DesktopAppBar(
isCompactHeight: false,
leading: AppBarBackButton(),
trailing: ExitToMyStackButton(),
)
: AppBar(
leading: AppBarBackButton(
onPressed: () {
if (textFieldFocusNode.hasFocus) {
textFieldFocusNode.unfocus();
Future<void>.delayed(const Duration(milliseconds: 100))
.then((value) => Navigator.of(context).pop());
} else {
Navigator.of(context).pop();
}
},
),
),
body: RestoreOptionsPlatformLayout(
isDesktop: isDesktop,
child: ConstrainedBox(
constraints: BoxConstraints(
maxWidth: isDesktop ? 480 : double.infinity,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Spacer(
flex: isDesktop ? 10 : 1,
),
if (!isDesktop)
Image(
image: AssetImage(
Assets.png.imageFor(coin: coin),
),
height: 100,
),
SizedBox(
height: isDesktop ? 0 : 16,
),
Text(
"Restore options",
textAlign: TextAlign.center,
style: isDesktop
? STextStyles.desktopH2(context)
: STextStyles.pageTitleH1(context),
),
SizedBox(
height: isDesktop ? 40 : 24,
),
if (coin == Coin.monero || coin == Coin.epicCash)
Text(
"Choose start date",
style: isDesktop
? STextStyles.desktopTextExtraSmall(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textDark3,
)
: STextStyles.smallMed12(context),
textAlign: TextAlign.left,
),
if (coin == Coin.monero || coin == Coin.epicCash)
SizedBox(
height: isDesktop ? 16 : 8,
),
if (coin == Coin.monero || coin == Coin.epicCash)
// if (!isDesktop)
RestoreFromDatePicker(
onTap: chooseDate,
),
// if (isDesktop)
// // TODO desktop date picker
if (coin == Coin.monero || coin == Coin.epicCash)
const SizedBox(
height: 8,
),
if (coin == Coin.monero || coin == Coin.epicCash)
RoundedWhiteContainer(
child: Center(
child: Text(
"Choose the date you made the wallet (approximate is fine)",
style: isDesktop
? STextStyles.desktopTextExtraSmall(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textSubtitle1,
)
: STextStyles.smallMed12(context).copyWith(
fontSize: 10,
),
),
),
),
if (coin == Coin.monero || coin == Coin.epicCash)
SizedBox(
height: isDesktop ? 24 : 16,
),
Text(
"Choose recovery phrase length",
style: isDesktop
? STextStyles.desktopTextExtraSmall(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textDark3,
)
: STextStyles.smallMed12(context),
textAlign: TextAlign.left,
),
SizedBox(
height: isDesktop ? 16 : 8,
),
if (isDesktop)
DropdownButtonHideUnderline(
child: DropdownButton2<int>(
value:
ref.watch(mnemonicWordCountStateProvider.state).state,
items: [
...lengths.map(
(e) => DropdownMenuItem(
value: e,
child: Text(
"$e words",
style: STextStyles.desktopTextMedium(context),
),
),
),
],
onChanged: (value) {
if (value is int) {
ref.read(mnemonicWordCountStateProvider.state).state =
value;
}
},
isExpanded: true,
icon: SvgPicture.asset(
Assets.svg.chevronDown,
width: 12,
height: 6,
color: Theme.of(context)
.extension<StackColors>()!
.textFieldActiveSearchIconRight,
),
buttonPadding: const EdgeInsets.symmetric(
horizontal: 16,
vertical: 8,
),
buttonDecoration: BoxDecoration(
color: Theme.of(context)
.extension<StackColors>()!
.textFieldDefaultBG,
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
),
),
dropdownDecoration: BoxDecoration(
color: Theme.of(context)
.extension<StackColors>()!
.textFieldDefaultBG,
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
),
),
),
),
if (!isDesktop)
MobileMnemonicLengthSelector(
chooseMnemonicLength: chooseMnemonicLength,
),
if (!isDesktop)
const Spacer(
flex: 3,
),
if (isDesktop)
const SizedBox(
height: 32,
),
RestoreOptionsNextButton(
isDesktop: isDesktop,
onPressed: _nextEnabled ? nextPressed : null,
),
if (isDesktop)
const Spacer(
flex: 15,
),
],
),
),
),
);
}
}

View file

@ -0,0 +1,60 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/svg.dart';
import 'package:stackwallet/providers/ui/verify_recovery_phrase/mnemonic_word_count_state_provider.dart';
import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
class MobileMnemonicLengthSelector extends ConsumerWidget {
const MobileMnemonicLengthSelector({
Key? key,
required this.chooseMnemonicLength,
}) : super(key: key);
final VoidCallback chooseMnemonicLength;
@override
Widget build(BuildContext context, WidgetRef ref) {
return Stack(
children: [
const TextField(
// controller: _lengthController,
readOnly: true,
textInputAction: TextInputAction.none,
),
Padding(
padding: const EdgeInsets.symmetric(
horizontal: 12,
),
child: RawMaterialButton(
splashColor: Theme.of(context).extension<StackColors>()!.highlight,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius,
),
),
onPressed: chooseMnemonicLength,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"${ref.watch(mnemonicWordCountStateProvider.state).state} words",
style: STextStyles.itemSubtitle12(context),
),
SvgPicture.asset(
Assets.svg.chevronDown,
width: 8,
height: 4,
color:
Theme.of(context).extension<StackColors>()!.textSubtitle2,
),
],
),
),
)
],
);
}
}

View file

@ -0,0 +1,76 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
class RestoreFromDatePicker extends StatefulWidget {
const RestoreFromDatePicker({Key? key, required this.onTap})
: super(key: key);
final VoidCallback onTap;
@override
State<RestoreFromDatePicker> createState() => _RestoreFromDatePickerState();
}
class _RestoreFromDatePickerState extends State<RestoreFromDatePicker> {
late final TextEditingController _dateController;
late final VoidCallback onTap;
@override
void initState() {
onTap = widget.onTap;
_dateController = TextEditingController();
super.initState();
}
@override
void dispose() {
_dateController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Container(
color: Colors.transparent,
child: TextField(
onTap: onTap,
controller: _dateController,
style: STextStyles.field(context),
decoration: InputDecoration(
hintText: "Restore from...",
suffixIcon: UnconstrainedBox(
child: Row(
children: [
const SizedBox(
width: 16,
),
SvgPicture.asset(
Assets.svg.calendar,
color: Theme.of(context).extension<StackColors>()!.textDark3,
width: 16,
height: 16,
),
const SizedBox(
width: 12,
),
],
),
),
),
key: const Key("restoreOptionsViewDatePickerKey"),
readOnly: true,
toolbarOptions: const ToolbarOptions(
copy: true,
cut: false,
paste: false,
selectAll: false,
),
onChanged: (newValue) {},
),
);
}
}

View file

@ -0,0 +1,37 @@
import 'package:flutter/material.dart';
import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
class RestoreOptionsNextButton extends StatelessWidget {
const RestoreOptionsNextButton({
Key? key,
required this.isDesktop,
this.onPressed,
}) : super(key: key);
final bool isDesktop;
final VoidCallback? onPressed;
@override
Widget build(BuildContext context) {
return ConstrainedBox(
constraints: BoxConstraints(
minHeight: isDesktop ? 70 : 0,
),
child: TextButton(
onPressed: onPressed,
style: onPressed != null
? Theme.of(context)
.extension<StackColors>()!
.getPrimaryEnabledButtonColor(context)
: Theme.of(context)
.extension<StackColors>()!
.getPrimaryDisabledButtonColor(context),
child: Text(
"Next",
style: STextStyles.button(context),
),
),
);
}
}

View file

@ -0,0 +1,39 @@
import 'package:flutter/material.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
class RestoreOptionsPlatformLayout extends StatelessWidget {
const RestoreOptionsPlatformLayout({
Key? key,
required this.isDesktop,
required this.child,
}) : super(key: key);
final bool isDesktop;
final Widget child;
@override
Widget build(BuildContext context) {
if (isDesktop) {
return child;
} else {
return Container(
color: Theme.of(context).extension<StackColors>()!.background,
child: Padding(
padding: const EdgeInsets.all(16),
child: LayoutBuilder(
builder: (ctx, constraints) {
return SingleChildScrollView(
child: ConstrainedBox(
constraints: BoxConstraints(minHeight: constraints.maxHeight),
child: IntrinsicHeight(
child: child,
),
),
);
},
),
),
);
}
}
}

View file

@ -1,9 +1,9 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:stackwallet/providers/ui/verify_recovery_phrase/mnemonic_word_count_state_provider.dart'; import 'package:stackwallet/providers/ui/verify_recovery_phrase/mnemonic_word_count_state_provider.dart';
import 'package:stackwallet/utilities/cfcolors.dart';
import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
class MnemonicWordCountSelectSheet extends ConsumerWidget { class MnemonicWordCountSelectSheet extends ConsumerWidget {
const MnemonicWordCountSelectSheet({ const MnemonicWordCountSelectSheet({
@ -22,9 +22,9 @@ class MnemonicWordCountSelectSheet extends ConsumerWidget {
return false; return false;
}, },
child: Container( child: Container(
decoration: const BoxDecoration( decoration: BoxDecoration(
color: CFColors.white, color: Theme.of(context).extension<StackColors>()!.popupBG,
borderRadius: BorderRadius.vertical( borderRadius: const BorderRadius.vertical(
top: Radius.circular(20), top: Radius.circular(20),
), ),
), ),
@ -42,7 +42,9 @@ class MnemonicWordCountSelectSheet extends ConsumerWidget {
Center( Center(
child: Container( child: Container(
decoration: BoxDecoration( decoration: BoxDecoration(
color: CFColors.fieldGray, color: Theme.of(context)
.extension<StackColors>()!
.textFieldDefaultBG,
borderRadius: BorderRadius.circular( borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius, Constants.size.circularBorderRadius,
), ),
@ -62,7 +64,7 @@ class MnemonicWordCountSelectSheet extends ConsumerWidget {
children: [ children: [
Text( Text(
"Phrase length", "Phrase length",
style: STextStyles.pageTitleH2, style: STextStyles.pageTitleH2(context),
textAlign: TextAlign.left, textAlign: TextAlign.left,
), ),
const SizedBox( const SizedBox(
@ -96,7 +98,9 @@ class MnemonicWordCountSelectSheet extends ConsumerWidget {
width: 20, width: 20,
height: 20, height: 20,
child: Radio( child: Radio(
activeColor: CFColors.link2, activeColor: Theme.of(context)
.extension<StackColors>()!
.radioButtonIconEnabled,
value: lengthOptions[i], value: lengthOptions[i],
groupValue: ref groupValue: ref
.watch(mnemonicWordCountStateProvider .watch(mnemonicWordCountStateProvider
@ -118,9 +122,7 @@ class MnemonicWordCountSelectSheet extends ConsumerWidget {
), ),
Text( Text(
"${lengthOptions[i]} words", "${lengthOptions[i]} words",
style: STextStyles.titleBold12.copyWith( style: STextStyles.titleBold12(context),
color: const Color(0xFF44464E),
),
textAlign: TextAlign.left, textAlign: TextAlign.left,
), ),
], ],

View file

@ -1,8 +1,8 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/providers/providers.dart';
import 'package:stackwallet/utilities/cfcolors.dart';
import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/widgets/stack_dialog.dart'; import 'package:stackwallet/widgets/stack_dialog.dart';
class RestoreFailedDialog extends ConsumerStatefulWidget { class RestoreFailedDialog extends ConsumerStatefulWidget {
@ -45,14 +45,12 @@ class _RestoreFailedDialogState extends ConsumerState<RestoreFailedDialog> {
title: "Restore failed", title: "Restore failed",
message: errorMessage, message: errorMessage,
rightButton: TextButton( rightButton: TextButton(
style: Theme.of(context).textButtonTheme.style?.copyWith( style: Theme.of(context)
backgroundColor: MaterialStateProperty.all<Color>( .extension<StackColors>()!
CFColors.buttonGray, .getSecondaryEnabledButtonColor(context),
),
),
child: Text( child: Text(
"Ok", "Ok",
style: STextStyles.itemSubtitle12, style: STextStyles.itemSubtitle12(context),
), ),
onPressed: () async { onPressed: () async {
ref ref

View file

@ -1,8 +1,12 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart'; import 'package:flutter_svg/svg.dart';
import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/cfcolors.dart';
import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/utilities/util.dart';
import 'package:stackwallet/widgets/desktop/desktop_dialog.dart';
import 'package:stackwallet/widgets/desktop/desktop_dialog_close_button.dart';
import 'package:stackwallet/widgets/desktop/primary_button.dart';
import 'package:stackwallet/widgets/stack_dialog.dart'; import 'package:stackwallet/widgets/stack_dialog.dart';
class RestoreSucceededDialog extends StatelessWidget { class RestoreSucceededDialog extends StatelessWidget {
@ -10,29 +14,82 @@ class RestoreSucceededDialog extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return StackDialog( if (Util.isDesktop) {
title: "Wallet restored", return DesktopDialog(
message: "You can use your wallet now.", child: Column(
icon: SvgPicture.asset( children: [
Assets.svg.checkCircle, const DesktopDialogCloseButton(),
width: 24, const Spacer(
height: 24, flex: 1,
color: CFColors.stackGreen, ),
), SvgPicture.asset(
rightButton: TextButton( Assets.svg.checkCircle,
style: Theme.of(context).textButtonTheme.style?.copyWith( width: 40,
backgroundColor: MaterialStateProperty.all<Color>( height: 40,
CFColors.buttonGray, color:
Theme.of(context).extension<StackColors>()!.accentColorDark,
),
const Spacer(
flex: 2,
),
Text(
"Wallet restored",
style: STextStyles.desktopH2(context),
textAlign: TextAlign.center,
),
const SizedBox(
height: 16,
),
Text(
"You can use your wallet now.",
style: STextStyles.desktopTextMedium(context).copyWith(
color: Theme.of(context).extension<StackColors>()!.textDark3,
),
textAlign: TextAlign.center,
),
const Spacer(
flex: 2,
),
Padding(
padding: const EdgeInsets.only(
left: 32,
right: 32,
bottom: 32,
),
child: PrimaryButton(
width: 272.5,
label: "OK",
onPressed: () {
Navigator.of(context).pop();
},
), ),
), ),
child: Text( ],
"Ok",
style: STextStyles.itemSubtitle12,
), ),
onPressed: () { );
Navigator.of(context).pop(); } else {
}, return StackDialog(
), title: "Wallet restored",
); message: "You can use your wallet now.",
icon: SvgPicture.asset(
Assets.svg.checkCircle,
width: 24,
height: 24,
color: Theme.of(context).extension<StackColors>()!.accentColorGreen,
),
rightButton: TextButton(
style: Theme.of(context)
.extension<StackColors>()!
.getSecondaryEnabledButtonColor(context),
child: Text(
"Ok",
style: STextStyles.itemSubtitle12(context),
),
onPressed: () {
Navigator.of(context).pop();
},
),
);
}
} }
} }

View file

@ -1,8 +1,12 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart'; import 'package:flutter_svg/svg.dart';
import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/cfcolors.dart';
import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/utilities/util.dart';
import 'package:stackwallet/widgets/desktop/desktop_dialog.dart';
import 'package:stackwallet/widgets/desktop/desktop_dialog_close_button.dart';
import 'package:stackwallet/widgets/desktop/secondary_button.dart';
import 'package:stackwallet/widgets/stack_dialog.dart'; import 'package:stackwallet/widgets/stack_dialog.dart';
class RestoringDialog extends StatefulWidget { class RestoringDialog extends StatefulWidget {
@ -50,40 +54,105 @@ class _RestoringDialogState extends State<RestoringDialog>
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return WillPopScope( if (Util.isDesktop) {
onWillPop: () async { return DesktopDialog(
return false; child: Column(
}, children: [
child: StackDialog( DesktopDialogCloseButton(
title: "Restoring wallet", onPressedOverride: () async {
message: "This may take a while. Please do not exit this screen.", await onCancel.call();
icon: RotationTransition( if (mounted) {
turns: _spinAnimation, Navigator.of(context).pop();
child: SvgPicture.asset( }
Assets.svg.arrowRotate3, },
width: 24, ),
height: 24, const Spacer(
color: CFColors.stackAccent, flex: 1,
), ),
), RotationTransition(
rightButton: TextButton( turns: _spinAnimation,
style: Theme.of(context).textButtonTheme.style?.copyWith( child: SvgPicture.asset(Assets.svg.arrowRotate3,
backgroundColor: MaterialStateProperty.all<Color>( width: 40,
CFColors.buttonGray, height: 40,
), color: Theme.of(context)
.extension<StackColors>()!
.accentColorDark),
),
const Spacer(
flex: 2,
),
Text(
"Restoring wallet...",
style: STextStyles.desktopH2(context),
textAlign: TextAlign.center,
),
const SizedBox(
height: 16,
),
Text(
"Restoring your wallet may take a while.\nPlease do not exit this screen.",
style: STextStyles.desktopTextMedium(context).copyWith(
color: Theme.of(context).extension<StackColors>()!.textDark3,
), ),
child: Text( textAlign: TextAlign.center,
"Cancel", ),
style: STextStyles.itemSubtitle12, const Spacer(
), flex: 2,
onPressed: () async { ),
await onCancel.call(); Padding(
if (mounted) { padding: const EdgeInsets.only(
Navigator.of(context).pop(); left: 32,
} right: 32,
}, bottom: 32,
),
child: SecondaryButton(
label: "Cancel",
width: 272.5,
onPressed: () async {
await onCancel.call();
if (mounted) {
Navigator.of(context).pop();
}
},
),
),
],
), ),
), );
); } else {
return WillPopScope(
onWillPop: () async {
return false;
},
child: StackDialog(
title: "Restoring wallet",
message: "This may take a while. Please do not exit this screen.",
icon: RotationTransition(
turns: _spinAnimation,
child: SvgPicture.asset(Assets.svg.arrowRotate3,
width: 24,
height: 24,
color: Theme.of(context)
.extension<StackColors>()!
.accentColorDark),
),
rightButton: TextButton(
style: Theme.of(context)
.extension<StackColors>()!
.getSecondaryEnabledButtonColor(context),
child: Text(
"Cancel",
style: STextStyles.itemSubtitle12(context),
),
onPressed: () async {
await onCancel.call();
if (mounted) {
Navigator.of(context).pop();
}
},
),
),
);
}
} }
} }

View file

@ -6,9 +6,11 @@ class WordTable extends ConsumerWidget {
const WordTable({ const WordTable({
Key? key, Key? key,
required this.words, required this.words,
required this.isDesktop,
}) : super(key: key); }) : super(key: key);
final List<String> words; final List<String> words;
final bool isDesktop;
static const wordsPerRow = 3; static const wordsPerRow = 3;
static const wordsToShow = 9; static const wordsToShow = 9;
@ -24,18 +26,19 @@ class WordTable extends ConsumerWidget {
children: [ children: [
for (int i = 1; i <= rows; i++) for (int i = 1; i <= rows; i++)
Padding( Padding(
padding: const EdgeInsets.symmetric(vertical: 5), padding: EdgeInsets.symmetric(vertical: isDesktop ? 8 : 5),
child: Row( child: Row(
children: [ children: [
for (int j = 1; j <= wordsPerRow; j++) ...[ for (int j = 1; j <= wordsPerRow; j++) ...[
if (j > 1) if (j > 1)
const SizedBox( SizedBox(
width: 6, width: isDesktop ? 10 : 6,
), ),
Expanded( Expanded(
child: WordTableItem( child: WordTableItem(
number: ++index, number: ++index,
word: words[index - 1], word: words[index - 1],
isDesktop: isDesktop,
), ),
), ),
], ],

View file

@ -1,19 +1,21 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/providers/providers.dart';
import 'package:stackwallet/utilities/cfcolors.dart';
import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
class WordTableItem extends ConsumerWidget { class WordTableItem extends ConsumerWidget {
const WordTableItem({ const WordTableItem({
Key? key, Key? key,
required this.number, required this.number,
required this.word, required this.word,
required this.isDesktop,
}) : super(key: key); }) : super(key: key);
final int number; final int number;
final String word; final String word;
final bool isDesktop;
@override @override
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
@ -22,15 +24,22 @@ class WordTableItem extends ConsumerWidget {
ref.watch(verifyMnemonicSelectedWordStateProvider.state).state; ref.watch(verifyMnemonicSelectedWordStateProvider.state).state;
return Container( return Container(
decoration: BoxDecoration( decoration: BoxDecoration(
color: selectedWord == word ? CFColors.selection : CFColors.white, color: selectedWord == word
? Theme.of(context).extension<StackColors>()!.snackBarBackInfo
: Theme.of(context).extension<StackColors>()!.popupBG,
borderRadius: BorderRadius.circular( borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius, Constants.size.circularBorderRadius,
), ),
), ),
child: MaterialButton( child: MaterialButton(
splashColor: CFColors.splashLight, splashColor: Theme.of(context).extension<StackColors>()!.highlight,
key: Key("coinSelectItemButtonKey_$word"), key: Key("coinSelectItemButtonKey_$word"),
padding: const EdgeInsets.all(12), padding: isDesktop
? const EdgeInsets.symmetric(
vertical: 18,
horizontal: 12,
)
: const EdgeInsets.all(12),
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: borderRadius:
@ -45,7 +54,25 @@ class WordTableItem extends ConsumerWidget {
Text( Text(
word, word,
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: STextStyles.baseXS, style: isDesktop
? STextStyles.desktopTextExtraSmall(context).copyWith(
color: selectedWord == word
? Theme.of(context)
.extension<StackColors>()!
.textSelectedWordTableItem
: Theme.of(context)
.extension<StackColors>()!
.textDark,
)
: STextStyles.baseXS(context).copyWith(
color: selectedWord == word
? Theme.of(context)
.extension<StackColors>()!
.textSelectedWordTableItem
: Theme.of(context)
.extension<StackColors>()!
.textDark,
),
), ),
], ],
), ),

View file

@ -1,3 +1,4 @@
import 'dart:async';
import 'dart:math'; import 'dart:math';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -6,14 +7,19 @@ import 'package:stackwallet/notifications/show_flush_bar.dart';
import 'package:stackwallet/pages/add_wallet_views/new_wallet_recovery_phrase_view/new_wallet_recovery_phrase_view.dart'; import 'package:stackwallet/pages/add_wallet_views/new_wallet_recovery_phrase_view/new_wallet_recovery_phrase_view.dart';
import 'package:stackwallet/pages/add_wallet_views/verify_recovery_phrase_view/sub_widgets/word_table.dart'; import 'package:stackwallet/pages/add_wallet_views/verify_recovery_phrase_view/sub_widgets/word_table.dart';
import 'package:stackwallet/pages/home_view/home_view.dart'; import 'package:stackwallet/pages/home_view/home_view.dart';
import 'package:stackwallet/pages_desktop_specific/home/desktop_home_view.dart';
import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/exit_to_my_stack_button.dart';
import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/providers/providers.dart';
import 'package:stackwallet/services/coins/manager.dart'; import 'package:stackwallet/services/coins/manager.dart';
import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/cfcolors.dart';
import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/enums/flush_bar_type.dart'; import 'package:stackwallet/utilities/enums/flush_bar_type.dart';
import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/utilities/util.dart';
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart';
import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
import 'package:tuple/tuple.dart'; import 'package:tuple/tuple.dart';
class VerifyRecoveryPhraseView extends ConsumerStatefulWidget { class VerifyRecoveryPhraseView extends ConsumerStatefulWidget {
@ -39,11 +45,13 @@ class _VerifyRecoveryPhraseViewState
{ {
late Manager _manager; late Manager _manager;
late List<String> _mnemonic; late List<String> _mnemonic;
late final bool isDesktop;
@override @override
void initState() { void initState() {
_manager = widget.manager; _manager = widget.manager;
_mnemonic = widget.mnemonic; _mnemonic = widget.mnemonic;
isDesktop = Util.isDesktop;
// WidgetsBinding.instance?.addObserver(this); // WidgetsBinding.instance?.addObserver(this);
super.initState(); super.initState();
} }
@ -75,6 +83,62 @@ class _VerifyRecoveryPhraseViewState
// } // }
// } // }
Future<void> _continue(bool isMatch) async {
if (isMatch) {
await ref.read(walletsServiceChangeNotifierProvider).setMnemonicVerified(
walletId: _manager.walletId,
);
ref
.read(walletsChangeNotifierProvider.notifier)
.addWallet(walletId: _manager.walletId, manager: _manager);
if (mounted) {
if (isDesktop) {
Navigator.of(context).popUntil(
ModalRoute.withName(
DesktopHomeView.routeName,
),
);
} else {
unawaited(
Navigator.of(context).pushNamedAndRemoveUntil(
HomeView.routeName,
(route) => false,
),
);
}
}
unawaited(showFloatingFlushBar(
type: FlushBarType.success,
message: "Correct! Your wallet is set up.",
iconAsset: Assets.svg.check,
context: context,
));
} else {
unawaited(showFloatingFlushBar(
type: FlushBarType.warning,
message: "Incorrect. Please try again.",
iconAsset: Assets.svg.circleX,
context: context,
));
final int next = Random().nextInt(_mnemonic.length);
ref
.read(verifyMnemonicWordIndexStateProvider.state)
.update((state) => next);
ref
.read(verifyMnemonicCorrectWordStateProvider.state)
.update((state) => _mnemonic[next]);
ref
.read(verifyMnemonicSelectedWordStateProvider.state)
.update((state) => "");
}
}
Tuple2<List<String>, String> randomize( Tuple2<List<String>, String> randomize(
List<String> mnemonic, int chosenIndex, int wordsToShow) { List<String> mnemonic, int chosenIndex, int wordsToShow) {
final List<String> remaining = []; final List<String> remaining = [];
@ -113,12 +177,12 @@ class _VerifyRecoveryPhraseViewState
return false; return false;
} }
// Future<void> delete() async { Future<void> delete() async {
// await ref await ref
// .read(walletsServiceChangeNotifierProvider) .read(walletsServiceChangeNotifierProvider)
// .deleteWallet(_manager.walletName, false); .deleteWallet(_manager.walletName, false);
// await _manager.exitCurrentWallet(); await _manager.exitCurrentWallet();
// } }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -128,51 +192,84 @@ class _VerifyRecoveryPhraseViewState
return WillPopScope( return WillPopScope(
onWillPop: onWillPop, onWillPop: onWillPop,
child: Scaffold( child: MasterScaffold(
appBar: AppBar( isDesktop: isDesktop,
leading: AppBarBackButton( appBar: isDesktop
onPressed: () async { ? DesktopAppBar(
// await delete(); isCompactHeight: false,
Navigator.of(context).popUntil( leading: AppBarBackButton(
ModalRoute.withName( onPressed: () async {
// NewWalletRecoveryPhraseWarningView.routeName, Navigator.of(context).popUntil(
NewWalletRecoveryPhraseView.routeName, ModalRoute.withName(
NewWalletRecoveryPhraseView.routeName,
),
);
},
), ),
); trailing: ExitToMyStackButton(
}, onPressed: () async {
), await delete();
), if (mounted) {
body: Container( Navigator.of(context).popUntil(
color: CFColors.almostWhite, ModalRoute.withName(DesktopHomeView.routeName),
);
}
},
),
)
: AppBar(
leading: AppBarBackButton(
onPressed: () async {
Navigator.of(context).popUntil(
ModalRoute.withName(
NewWalletRecoveryPhraseView.routeName,
),
);
},
),
),
body: SizedBox(
width: isDesktop ? 410 : null,
child: Padding( child: Padding(
padding: const EdgeInsets.all(16), padding:
isDesktop ? const EdgeInsets.all(0) : const EdgeInsets.all(16),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
const SizedBox( if (isDesktop)
height: 4, const Spacer(
flex: 10,
),
SizedBox(
height: isDesktop ? 24 : 4,
), ),
Text( Text(
"Verify recovery phrase", "Verify recovery phrase",
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: STextStyles.label.copyWith( style: isDesktop
fontSize: 12, ? STextStyles.desktopH2(context)
), : STextStyles.label(context).copyWith(
fontSize: 12,
),
), ),
const SizedBox( SizedBox(
height: 4, height: isDesktop ? 16 : 4,
), ),
Text( Text(
"Tap word number ", isDesktop ? "Select word number" : "Tap word number ",
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: STextStyles.pageTitleH1, style: isDesktop
? STextStyles.desktopSubtitleH1(context)
: STextStyles.pageTitleH1(context),
), ),
const SizedBox( SizedBox(
height: 12, height: isDesktop ? 16 : 12,
), ),
Container( Container(
decoration: BoxDecoration( decoration: BoxDecoration(
color: CFColors.fieldGray, color: Theme.of(context)
.extension<StackColors>()!
.textFieldDefaultBG,
borderRadius: BorderRadius.circular( borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius), Constants.size.circularBorderRadius),
), ),
@ -184,18 +281,26 @@ class _VerifyRecoveryPhraseViewState
child: Text( child: Text(
"${correctIndex + 1}", "${correctIndex + 1}",
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: STextStyles.subtitle.copyWith( style: STextStyles.subtitle600(context).copyWith(
fontWeight: FontWeight.w600,
fontSize: 32, fontSize: 32,
letterSpacing: 0.25, letterSpacing: 0.25,
), ),
), ),
), ),
), ),
if (isDesktop)
const SizedBox(
height: 40,
),
WordTable( WordTable(
words: randomize(_mnemonic, correctIndex, 9).item1, words: randomize(_mnemonic, correctIndex, 9).item1,
isDesktop: isDesktop,
), ),
const Spacer(), if (!isDesktop) const Spacer(),
if (isDesktop)
const SizedBox(
height: 40,
),
Row( Row(
children: [ children: [
Expanded( Expanded(
@ -210,92 +315,37 @@ class _VerifyRecoveryPhraseViewState
verifyMnemonicCorrectWordStateProvider.state) verifyMnemonicCorrectWordStateProvider.state)
.state; .state;
return TextButton( return ConstrainedBox(
onPressed: selectedWord.isNotEmpty constraints: BoxConstraints(
? () async { minHeight: isDesktop ? 70 : 0,
if (correctWord == selectedWord) { ),
await ref child: TextButton(
.read( onPressed: selectedWord.isNotEmpty
walletsServiceChangeNotifierProvider) ? () async {
.setMnemonicVerified( await _continue(
walletId: _manager.walletId, correctWord == selectedWord);
);
ref
.read(walletsChangeNotifierProvider
.notifier)
.addWallet(
walletId: _manager.walletId,
manager: _manager);
if (mounted) {
Navigator.of(context)
.pushNamedAndRemoveUntil(
HomeView.routeName,
(route) => false);
}
showFloatingFlushBar(
type: FlushBarType.success,
message:
"Correct! Your wallet is set up.",
iconAsset: Assets.svg.check,
context: context,
);
} else {
showFloatingFlushBar(
type: FlushBarType.warning,
message: "Incorrect. Please try again.",
iconAsset: Assets.svg.circleX,
context: context,
);
final int next =
Random().nextInt(_mnemonic.length);
ref
.read(
verifyMnemonicWordIndexStateProvider
.state)
.update((state) => next);
ref
.read(
verifyMnemonicCorrectWordStateProvider
.state)
.update((state) => _mnemonic[next]);
ref
.read(
verifyMnemonicSelectedWordStateProvider
.state)
.update((state) => "");
} }
} : null,
: null, style: selectedWord.isNotEmpty
style: selectedWord.isNotEmpty ? Theme.of(context)
? Theme.of(context) .extension<StackColors>()!
.textButtonTheme .getPrimaryEnabledButtonColor(context)
.style : Theme.of(context)
?.copyWith( .extension<StackColors>()!
backgroundColor: .getPrimaryDisabledButtonColor(context),
MaterialStateProperty.all<Color>( child: isDesktop
CFColors.stackAccent, ? Text(
), "Verify",
style: selectedWord.isNotEmpty
? STextStyles.desktopButtonEnabled(
context)
: STextStyles.desktopButtonDisabled(
context),
) )
: Theme.of(context) : Text(
.textButtonTheme "Continue",
.style style: STextStyles.button(context),
?.copyWith(
backgroundColor:
MaterialStateProperty.all<Color>(
CFColors.stackAccent.withOpacity(
0.25,
),
),
), ),
child: Text(
"Continue",
style: STextStyles.button,
), ),
); );
}, },
@ -303,6 +353,10 @@ class _VerifyRecoveryPhraseViewState
), ),
], ],
), ),
if (isDesktop)
const Spacer(
flex: 15,
),
], ],
), ),
), ),

View file

@ -9,10 +9,10 @@ import 'package:stackwallet/providers/global/address_book_service_provider.dart'
import 'package:stackwallet/providers/providers.dart'; import 'package:stackwallet/providers/providers.dart';
import 'package:stackwallet/providers/ui/address_book_providers/address_book_filter_provider.dart'; import 'package:stackwallet/providers/ui/address_book_providers/address_book_filter_provider.dart';
import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/cfcolors.dart';
import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart';
import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/widgets/address_book_card.dart'; import 'package:stackwallet/widgets/address_book_card.dart';
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart'; import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
import 'package:stackwallet/widgets/icon_widgets/x_icon.dart'; import 'package:stackwallet/widgets/icon_widgets/x_icon.dart';
@ -102,7 +102,7 @@ class _AddressBookViewState extends ConsumerState<AddressBookView> {
addressBookServiceProvider.select((value) => value.addressBookEntries)); addressBookServiceProvider.select((value) => value.addressBookEntries));
return Scaffold( return Scaffold(
backgroundColor: CFColors.almostWhite, backgroundColor: Theme.of(context).extension<StackColors>()!.background,
appBar: AppBar( appBar: AppBar(
leading: AppBarBackButton( leading: AppBarBackButton(
onPressed: () { onPressed: () {
@ -111,7 +111,7 @@ class _AddressBookViewState extends ConsumerState<AddressBookView> {
), ),
title: Text( title: Text(
"Address book", "Address book",
style: STextStyles.navBarTitle, style: STextStyles.navBarTitle(context),
), ),
actions: [ actions: [
Padding( Padding(
@ -126,10 +126,12 @@ class _AddressBookViewState extends ConsumerState<AddressBookView> {
key: const Key("addressBookFilterViewButton"), key: const Key("addressBookFilterViewButton"),
size: 36, size: 36,
shadows: const [], shadows: const [],
color: CFColors.almostWhite, color: Theme.of(context).extension<StackColors>()!.background,
icon: SvgPicture.asset( icon: SvgPicture.asset(
Assets.svg.filter, Assets.svg.filter,
color: CFColors.stackAccent, color: Theme.of(context)
.extension<StackColors>()!
.accentColorDark,
width: 20, width: 20,
height: 20, height: 20,
), ),
@ -153,10 +155,12 @@ class _AddressBookViewState extends ConsumerState<AddressBookView> {
key: const Key("addressBookAddNewContactViewButton"), key: const Key("addressBookAddNewContactViewButton"),
size: 36, size: 36,
shadows: const [], shadows: const [],
color: CFColors.almostWhite, color: Theme.of(context).extension<StackColors>()!.background,
icon: SvgPicture.asset( icon: SvgPicture.asset(
Assets.svg.plus, Assets.svg.plus,
color: CFColors.stackAccent, color: Theme.of(context)
.extension<StackColors>()!
.accentColorDark,
width: 20, width: 20,
height: 20, height: 20,
), ),
@ -201,10 +205,11 @@ class _AddressBookViewState extends ConsumerState<AddressBookView> {
_searchTerm = value; _searchTerm = value;
}); });
}, },
style: STextStyles.field, style: STextStyles.field(context),
decoration: standardInputDecoration( decoration: standardInputDecoration(
"Search", "Search",
_searchFocusNode, _searchFocusNode,
context,
).copyWith( ).copyWith(
prefixIcon: Padding( prefixIcon: Padding(
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
@ -244,7 +249,7 @@ class _AddressBookViewState extends ConsumerState<AddressBookView> {
), ),
Text( Text(
"Favorites", "Favorites",
style: STextStyles.smallMed12, style: STextStyles.smallMed12(context),
), ),
const SizedBox( const SizedBox(
height: 12, height: 12,
@ -297,7 +302,7 @@ class _AddressBookViewState extends ConsumerState<AddressBookView> {
child: Center( child: Center(
child: Text( child: Text(
"Your favorite contacts will appear here", "Your favorite contacts will appear here",
style: STextStyles.itemSubtitle, style: STextStyles.itemSubtitle(context),
), ),
), ),
); );
@ -310,7 +315,7 @@ class _AddressBookViewState extends ConsumerState<AddressBookView> {
), ),
Text( Text(
"All contacts", "All contacts",
style: STextStyles.smallMed12, style: STextStyles.smallMed12(context),
), ),
const SizedBox( const SizedBox(
height: 12, height: 12,
@ -360,7 +365,7 @@ class _AddressBookViewState extends ConsumerState<AddressBookView> {
child: Center( child: Center(
child: Text( child: Text(
"Your contacts will appear here", "Your contacts will appear here",
style: STextStyles.itemSubtitle, style: STextStyles.itemSubtitle(context),
), ),
), ),
); );

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