Merge pull request #881 from cypherstack/campfire

All the things
This commit is contained in:
julian-CStack 2024-06-05 13:45:36 -06:00 committed by GitHub
commit 223e8509a2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
695 changed files with 12266 additions and 8343 deletions

22
.gitignore vendored
View file

@ -96,3 +96,25 @@ pubspec.yaml
/windows/runner/main.cpp /windows/runner/main.cpp
/windows/CMakeLists.txt /windows/CMakeLists.txt
/windows/runner/resources/app_icon.ico /windows/runner/resources/app_icon.ico
# FVM Version Cache
.fvm/
android/app/src/main/jniLibs/arm64-v8a/libwownero_wallet2_api_c.so
android/app/src/main/jniLibs/arm64-v8a/libmonero_wallet2_api_c.so
android/app/src/main/jniLibs/armeabi-v7a/libmonero_wallet2_api_c.so
android/app/src/main/jniLibs/armeabi-v7a/libwownero_wallet2_api_c.so
android/app/src/main/jniLibs/x86_64/libmonero_wallet2_api_c.so
android/app/src/main/jniLibs/x86_64/libwownero_wallet2_api_c.so
macos/monero_wallet2_api_c.dylib
macos/wownero_wallet2_api_c.dylib
/macos/monero_libwallet2_api_c.dylib
/macos/wownero_libwallet2_api_c.dylib
/ios/monero_libwallet2_api_c.dylib
/ios/wownero_libwallet2_api_c.dylib
/android/app/src/main/jniLibs/arm64-v8a/libmonero_libwallet2_api_c.so
/android/app/src/main/jniLibs/armeabi-v7a/libmonero_libwallet2_api_c.so
/android/app/src/main/jniLibs/x86_64/libmonero_libwallet2_api_c.so
/android/app/src/main/jniLibs/arm64-v8a/libwownero_libwallet2_api_c.so
/android/app/src/main/jniLibs/armeabi-v7a/libwownero_libwallet2_api_c.so
/android/app/src/main/jniLibs/x86_64/libwownero_libwallet2_api_c.so

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

View file

@ -0,0 +1,9 @@
<svg width="72" height="84" viewBox="0 0 72 84" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M1.12967 68.765C0.433381 71.2717 0.414629 73.9187 1.07535 76.435C1.73607 78.9513 3.05254 81.2466 4.89 83.086L15.2595 72.7011L4.89 62.3129C3.10079 64.102 1.80521 66.325 1.12967 68.765ZM56.7407 72.6913L67.1134 83.0762C68.4759 81.7125 69.5568 80.0934 70.2942 78.3112C71.0316 76.529 71.4112 74.6188 71.4112 72.6896C71.4112 70.7605 71.0316 68.8503 70.2942 67.0681C69.5568 65.2859 68.4759 63.6667 67.1134 62.3031L56.7407 72.6913ZM36.0017 62.3129L25.6322 51.928L4.89 31.1581C2.14007 33.9125 0.595189 37.648 0.595189 41.543C0.595189 45.438 2.14007 49.1736 4.89 51.928L25.6322 72.7011C28.3829 75.4543 32.1127 77.0009 36.0017 77.0009C39.8907 77.0009 43.6205 75.4543 46.3712 72.7011L67.1134 51.928C69.8625 49.1731 71.4069 45.4378 71.4069 41.543C71.4069 37.6482 69.8625 33.9129 67.1134 31.1581L36.0017 62.3129ZM36.0017 31.1581C34.6393 32.5215 33.5585 34.1404 32.8212 35.9223C32.0838 37.7042 31.7042 39.6141 31.7042 41.543C31.7042 43.4719 32.0838 45.3818 32.8212 47.1637C33.5585 48.9456 34.6393 50.5646 36.0017 51.928L51.556 36.3505C52.9185 34.9869 53.9993 33.3677 54.7368 31.5855C55.4742 29.8033 55.8537 27.8931 55.8537 25.964C55.8537 24.0348 55.4742 22.1246 54.7368 20.3424C53.9993 18.5603 52.9185 16.9411 51.556 15.5774L36.0017 31.1581ZM20.4474 15.5774C19.0853 16.9413 18.0049 18.5605 17.2677 20.3427C16.5305 22.1248 16.151 24.035 16.151 25.964C16.151 27.893 16.5305 29.8031 17.2677 31.5853C18.0049 33.3674 19.0853 34.9866 20.4474 36.3505L36.0017 20.7699C37.3641 19.4065 38.4449 17.7876 39.1823 16.0057C39.9196 14.2238 40.2992 12.3138 40.2992 10.3849C40.2992 8.45606 39.9196 6.5461 39.1823 4.7642C38.4449 2.9823 37.3641 1.36339 36.0017 0L20.4474 15.5774Z" fill="url(#paint0_linear_243_16074)"/>
<defs>
<linearGradient id="paint0_linear_243_16074" x1="36.0017" y1="0" x2="36.0017" y2="83.086" gradientUnits="userSpaceOnUse">
<stop stop-color="#F5595C"/>
<stop offset="1" stop-color="#F94167"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2 KiB

View file

@ -0,0 +1,9 @@
<svg width="72" height="84" viewBox="0 0 72 84" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M1.12967 68.765C0.433381 71.2717 0.414629 73.9187 1.07535 76.435C1.73607 78.9513 3.05254 81.2466 4.89 83.086L15.2595 72.7011L4.89 62.3129C3.10079 64.102 1.80521 66.325 1.12967 68.765ZM56.7407 72.6913L67.1134 83.0762C68.4759 81.7125 69.5568 80.0934 70.2942 78.3112C71.0316 76.529 71.4112 74.6188 71.4112 72.6896C71.4112 70.7605 71.0316 68.8503 70.2942 67.0681C69.5568 65.2859 68.4759 63.6667 67.1134 62.3031L56.7407 72.6913ZM36.0017 62.3129L25.6322 51.928L4.89 31.1581C2.14007 33.9125 0.595189 37.648 0.595189 41.543C0.595189 45.438 2.14007 49.1736 4.89 51.928L25.6322 72.7011C28.3829 75.4543 32.1127 77.0009 36.0017 77.0009C39.8907 77.0009 43.6205 75.4543 46.3712 72.7011L67.1134 51.928C69.8625 49.1731 71.4069 45.4378 71.4069 41.543C71.4069 37.6482 69.8625 33.9129 67.1134 31.1581L36.0017 62.3129ZM36.0017 31.1581C34.6393 32.5215 33.5585 34.1404 32.8212 35.9223C32.0838 37.7042 31.7042 39.6141 31.7042 41.543C31.7042 43.4719 32.0838 45.3818 32.8212 47.1637C33.5585 48.9456 34.6393 50.5646 36.0017 51.928L51.556 36.3505C52.9185 34.9869 53.9993 33.3677 54.7368 31.5855C55.4742 29.8033 55.8537 27.8931 55.8537 25.964C55.8537 24.0348 55.4742 22.1246 54.7368 20.3424C53.9993 18.5603 52.9185 16.9411 51.556 15.5774L36.0017 31.1581ZM20.4474 15.5774C19.0853 16.9413 18.0049 18.5605 17.2677 20.3427C16.5305 22.1248 16.151 24.035 16.151 25.964C16.151 27.893 16.5305 29.8031 17.2677 31.5853C18.0049 33.3674 19.0853 34.9866 20.4474 36.3505L36.0017 20.7699C37.3641 19.4065 38.4449 17.7876 39.1823 16.0057C39.9196 14.2238 40.2992 12.3138 40.2992 10.3849C40.2992 8.45606 39.9196 6.5461 39.1823 4.7642C38.4449 2.9823 37.3641 1.36339 36.0017 0L20.4474 15.5774Z" fill="url(#paint0_linear_243_16074)"/>
<defs>
<linearGradient id="paint0_linear_243_16074" x1="36.0017" y1="0" x2="36.0017" y2="83.086" gradientUnits="userSpaceOnUse">
<stop stop-color="#F5595C"/>
<stop offset="1" stop-color="#F94167"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2 KiB

View file

@ -0,0 +1 @@
{"v":"5.10.2","fr":30,"ip":0,"op":60,"w":30,"h":30,"nm":"arrow-rotate","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"arrow-rotate","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":44,"s":[200]},{"t":60,"s":[360]}],"ix":10},"p":{"a":0,"k":[15,15,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-0.828],[0,0],[3.389,0],[1.441,-4.074],[-0.781,-0.277],[-0.276,0.778],[-3.22,0],[-1.369,-1.823],[0,0],[0,-0.83],[-0.83,0],[0,0],[-0.023,0],[0,0],[0,0.83],[0,0],[0.83,0]],"o":[[0,0],[-1.964,-2.437],[-4.533,0],[-0.276,0.741],[0.781,0.277],[1.031,-2.916],[2.494,0],[0,0],[-0.83,0],[0,0.83],[0,0],[0.023,0],[0,0],[0.83,0],[0,0],[0,-0.828],[-0.83,0]],"v":[[8.25,-8.25],[8.25,-6.497],[-0.042,-10.5],[-9.902,-3.502],[-8.988,-1.584],[-7.073,-2.498],[-0.042,-7.5],[6,-4.5],[4.5,-4.5],[3,-3],[4.5,-1.5],[8.452,-1.5],[8.522,-1.5],[9.75,-1.5],[11.25,-3],[11.25,-8.25],[9.75,-9.75]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,0],[-0.828,0],[0,0.83],[0,0],[-3.347,0],[-1.439,4.073],[0.783,0.277],[0.277,-0.778],[3.262,0],[1.411,1.823],[0,0],[0,0.83],[0.83,0],[0,0],[0,-0.83]],"o":[[0,0.83],[0.828,0],[0,0],[1.922,2.438],[4.575,0],[0.277,-0.783],[-0.778,-0.277],[-1.031,2.916],[-2.452,0],[0,0],[0.83,0],[0,-0.83],[0,0],[-0.828,0],[0,0]],"v":[[-11.25,8.25],[-9.75,9.75],[-8.25,8.25],[-8.25,6.497],[0,10.5],[9.9,3.502],[8.986,1.584],[7.073,2.498],[0,7.5],[-6.042,4.5],[-4.5,4.5],[-3,3],[-4.5,1.5],[-9.75,1.5],[-11.25,3]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0.137254908681,0.137254908681,0.137254908681,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":60,"st":0,"ct":1,"bm":0}],"markers":[]}

View file

@ -0,0 +1 @@
{"v":"5.10.2","fr":30,"ip":0,"op":100,"w":24,"h":24,"nm":"icon-send","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"MASK","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[12,12,0],"ix":2,"l":2},"a":{"a":0,"k":[0.125,0.125,0],"ix":1,"l":2},"s":{"a":0,"k":[87.368,87.368,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[23.75,23.75],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0.125,0.125],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":100,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Arrow","tt":1,"tp":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[-1.009,25.009,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":33,"s":[11.695,12.306,0],"to":[0,0,0],"ti":[0,0,0]},{"t":53,"s":[24.398,-0.397,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,-0.69],[-0.69,0],[0,0],[0,0],[-0.488,-0.488],[-0.488,0.488],[0,0],[0,0],[-0.69,0],[0,0.69],[0,0],[0.234,0.234],[0.332,0]],"o":[[-0.69,0],[0,0.69],[0,0],[0,0],[-0.488,0.488],[0.488,0.488],[0,0],[0,0],[0,0.69],[0.69,0],[0,0],[0,-0.332],[-0.234,-0.234],[0,0]],"v":[[-2,-5.25],[-3.25,-4],[-2,-2.75],[0.982,-2.75],[-4.884,3.116],[-4.884,4.884],[-3.116,4.884],[2.75,-0.982],[2.75,2],[4,3.25],[5.25,2],[5.25,-4],[4.884,-4.884],[4,-5.25]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.137254908681,0.137254908681,0.137254908681,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector (Stroke)","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":100,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Outline","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[12,12,0],"ix":2,"l":2},"a":{"a":0,"k":[12,0.063,0],"ix":1,"l":2},"s":{"a":0,"k":[90.104,90.104,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[24,24],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.137254901961,0.137254901961,0.137254901961,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2.5,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[12,0.063],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":58,"s":[0]},{"t":97,"s":[100]}],"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":58,"s":[100]},{"t":97,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":0,"op":100,"st":0,"ct":1,"bm":0}],"markers":[{"tm":0,"cm":"{\r\n\"name\":\"SEGMENT 1\"\r\n}","dr":0},{"tm":53,"cm":"{\r\n\"name\":\"SEGMENT 2\"\r\n}","dr":0},{"tm":97,"cm":"{\r\n\"name\":\"SEGMENT 3\"\r\n}","dr":0}]}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

@ -1 +1 @@
Subproject commit 6e71b956c3801f65a662c7f140e871c246166db3 Subproject commit 4b87151d4914606b911f738a8236a6e54a6d8ecb

View file

@ -53,7 +53,7 @@ sudo apt-get install libc6:i386 libncurses5:i386 libstdc++6:i386 lib32z1 libbz2-
### Build dependencies ### Build dependencies
Install basic dependencies Install basic dependencies
``` ```
sudo apt-get install libssl-dev curl unzip automake build-essential file pkg-config git python libtool libtinfo5 cmake libgit2-dev clang libncurses5-dev libncursesw5-dev zlib1g-dev llvm python3-distutils sudo apt-get install libssl-dev curl unzip automake build-essential file pkg-config git python libtool libtinfo5 cmake libgit2-dev clang libncurses5-dev libncursesw5-dev zlib1g-dev llvm python3-distutils g++ gcc gperf
``` ```
Install [Rust](https://www.rust-lang.org/tools/install) with command: Install [Rust](https://www.rust-lang.org/tools/install) with command:
@ -180,7 +180,7 @@ Download and install [Homebrew](https://brew.sh/). The following command can in
After installing Homebrew, install the following packages: After installing Homebrew, install the following packages:
``` ```
brew install autoconf automake boost berkeley-db ca-certificates cbindgen cmake cmake cocoapods curl git libssh2 make openssl@1.1 openssl@3 perl pkg-config rustup-init sodium unbound unzip xz zmq brew install autoconf automake boost berkeley-db ca-certificates cbindgen cmake cocoapods curl git libssh2 libsodium make openssl@1.1 openssl@3 perl pkg-config rustup-init unbound unzip xz zmq
``` ```
The following brew formula *may* be needed: The following brew formula *may* be needed:

View file

@ -9,63 +9,6 @@ PODS:
- connectivity_plus (0.0.1): - connectivity_plus (0.0.1):
- Flutter - Flutter
- ReachabilitySwift - ReachabilitySwift
- cw_monero (0.0.2):
- cw_monero/Boost (= 0.0.2)
- cw_monero/Monero (= 0.0.2)
- cw_monero/OpenSSL (= 0.0.2)
- cw_monero/Sodium (= 0.0.2)
- cw_monero/Unbound (= 0.0.2)
- cw_shared_external
- Flutter
- cw_monero/Boost (0.0.2):
- cw_shared_external
- Flutter
- cw_monero/Monero (0.0.2):
- cw_shared_external
- Flutter
- cw_monero/OpenSSL (0.0.2):
- cw_shared_external
- Flutter
- cw_monero/Sodium (0.0.2):
- cw_shared_external
- Flutter
- cw_monero/Unbound (0.0.2):
- cw_shared_external
- Flutter
- cw_shared_external (0.0.1):
- cw_shared_external/Boost (= 0.0.1)
- cw_shared_external/OpenSSL (= 0.0.1)
- cw_shared_external/Sodium (= 0.0.1)
- Flutter
- cw_shared_external/Boost (0.0.1):
- Flutter
- cw_shared_external/OpenSSL (0.0.1):
- Flutter
- cw_shared_external/Sodium (0.0.1):
- Flutter
- cw_wownero (0.0.2):
- cw_shared_external
- cw_wownero/Boost (= 0.0.2)
- cw_wownero/OpenSSL (= 0.0.2)
- cw_wownero/Sodium (= 0.0.2)
- cw_wownero/Unbound (= 0.0.2)
- cw_wownero/Wownero (= 0.0.2)
- Flutter
- cw_wownero/Boost (0.0.2):
- cw_shared_external
- Flutter
- cw_wownero/OpenSSL (0.0.2):
- cw_shared_external
- Flutter
- cw_wownero/Sodium (0.0.2):
- cw_shared_external
- Flutter
- cw_wownero/Unbound (0.0.2):
- cw_shared_external
- Flutter
- cw_wownero/Wownero (0.0.2):
- cw_shared_external
- Flutter
- device_info_plus (0.0.1): - device_info_plus (0.0.1):
- Flutter - Flutter
- devicelocale (0.0.1): - devicelocale (0.0.1):
@ -140,6 +83,21 @@ PODS:
- SDWebImage/Core (5.13.2) - SDWebImage/Core (5.13.2)
- share_plus (0.0.1): - share_plus (0.0.1):
- Flutter - Flutter
- sqlite3 (3.46.0):
- sqlite3/common (= 3.46.0)
- sqlite3/common (3.46.0)
- sqlite3/fts5 (3.46.0):
- sqlite3/common
- sqlite3/perf-threadsafe (3.46.0):
- sqlite3/common
- sqlite3/rtree (3.46.0):
- sqlite3/common
- sqlite3_flutter_libs (0.0.1):
- Flutter
- sqlite3 (~> 3.46.0)
- sqlite3/fts5
- sqlite3/perf-threadsafe
- sqlite3/rtree
- stack_wallet_backup (0.0.1): - stack_wallet_backup (0.0.1):
- Flutter - Flutter
- SwiftProtobuf (1.19.0) - SwiftProtobuf (1.19.0)
@ -155,9 +113,6 @@ DEPENDENCIES:
- barcode_scan2 (from `.symlinks/plugins/barcode_scan2/ios`) - barcode_scan2 (from `.symlinks/plugins/barcode_scan2/ios`)
- coinlib_flutter (from `.symlinks/plugins/coinlib_flutter/darwin`) - coinlib_flutter (from `.symlinks/plugins/coinlib_flutter/darwin`)
- connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`) - connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`)
- cw_monero (from `.symlinks/plugins/cw_monero/ios`)
- cw_shared_external (from `.symlinks/plugins/cw_shared_external/ios`)
- cw_wownero (from `.symlinks/plugins/cw_wownero/ios`)
- device_info_plus (from `.symlinks/plugins/device_info_plus/ios`) - device_info_plus (from `.symlinks/plugins/device_info_plus/ios`)
- devicelocale (from `.symlinks/plugins/devicelocale/ios`) - devicelocale (from `.symlinks/plugins/devicelocale/ios`)
- file_picker (from `.symlinks/plugins/file_picker/ios`) - file_picker (from `.symlinks/plugins/file_picker/ios`)
@ -177,6 +132,7 @@ DEPENDENCIES:
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`) - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
- permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`) - permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`)
- share_plus (from `.symlinks/plugins/share_plus/ios`) - share_plus (from `.symlinks/plugins/share_plus/ios`)
- sqlite3_flutter_libs (from `.symlinks/plugins/sqlite3_flutter_libs/ios`)
- stack_wallet_backup (from `.symlinks/plugins/stack_wallet_backup/ios`) - stack_wallet_backup (from `.symlinks/plugins/stack_wallet_backup/ios`)
- tor_ffi_plugin (from `.symlinks/plugins/tor_ffi_plugin/ios`) - tor_ffi_plugin (from `.symlinks/plugins/tor_ffi_plugin/ios`)
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
@ -189,6 +145,7 @@ SPEC REPOS:
- MTBBarcodeScanner - MTBBarcodeScanner
- ReachabilitySwift - ReachabilitySwift
- SDWebImage - SDWebImage
- sqlite3
- SwiftProtobuf - SwiftProtobuf
- SwiftyGif - SwiftyGif
@ -199,12 +156,6 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/coinlib_flutter/darwin" :path: ".symlinks/plugins/coinlib_flutter/darwin"
connectivity_plus: connectivity_plus:
:path: ".symlinks/plugins/connectivity_plus/ios" :path: ".symlinks/plugins/connectivity_plus/ios"
cw_monero:
:path: ".symlinks/plugins/cw_monero/ios"
cw_shared_external:
:path: ".symlinks/plugins/cw_shared_external/ios"
cw_wownero:
:path: ".symlinks/plugins/cw_wownero/ios"
device_info_plus: device_info_plus:
:path: ".symlinks/plugins/device_info_plus/ios" :path: ".symlinks/plugins/device_info_plus/ios"
devicelocale: devicelocale:
@ -243,6 +194,8 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/permission_handler_apple/ios" :path: ".symlinks/plugins/permission_handler_apple/ios"
share_plus: share_plus:
:path: ".symlinks/plugins/share_plus/ios" :path: ".symlinks/plugins/share_plus/ios"
sqlite3_flutter_libs:
:path: ".symlinks/plugins/sqlite3_flutter_libs/ios"
stack_wallet_backup: stack_wallet_backup:
:path: ".symlinks/plugins/stack_wallet_backup/ios" :path: ".symlinks/plugins/stack_wallet_backup/ios"
tor_ffi_plugin: tor_ffi_plugin:
@ -256,9 +209,6 @@ SPEC CHECKSUMS:
barcode_scan2: 0af2bb63c81b4565aab6cd78278e4c0fa136dbb0 barcode_scan2: 0af2bb63c81b4565aab6cd78278e4c0fa136dbb0
coinlib_flutter: 6abec900d67762a6e7ccfd567a3cd3ae00bbee35 coinlib_flutter: 6abec900d67762a6e7ccfd567a3cd3ae00bbee35
connectivity_plus: 07c49e96d7fc92bc9920617b83238c4d178b446a connectivity_plus: 07c49e96d7fc92bc9920617b83238c4d178b446a
cw_monero: 9816991daff0e3ad0a8be140e31933b5526babd4
cw_shared_external: 2972d872b8917603478117c9957dfca611845a92
cw_wownero: ac53899fa5c6ff46b3fb490aa3b7ca36301fa832
device_info_plus: 7545d84d8d1b896cb16a4ff98c19f07ec4b298ea device_info_plus: 7545d84d8d1b896cb16a4ff98c19f07ec4b298ea
devicelocale: b22617f40038496deffba44747101255cee005b0 devicelocale: b22617f40038496deffba44747101255cee005b0
DKImagePickerController: b512c28220a2b8ac7419f21c491fc8534b7601ac DKImagePickerController: b512c28220a2b8ac7419f21c491fc8534b7601ac
@ -283,6 +233,8 @@ SPEC CHECKSUMS:
ReachabilitySwift: 985039c6f7b23a1da463388634119492ff86c825 ReachabilitySwift: 985039c6f7b23a1da463388634119492ff86c825
SDWebImage: 72f86271a6f3139cc7e4a89220946489d4b9a866 SDWebImage: 72f86271a6f3139cc7e4a89220946489d4b9a866
share_plus: 599aa54e4ea31d4b4c0e9c911bcc26c55e791028 share_plus: 599aa54e4ea31d4b4c0e9c911bcc26c55e791028
sqlite3: 154b084339ede06960a5b3c8160066adc9176b7d
sqlite3_flutter_libs: 0d611efdf6d1c9297d5ab03dab21b75aeebdae31
stack_wallet_backup: 5b8563aba5d8ffbf2ce1944331ff7294a0ec7c03 stack_wallet_backup: 5b8563aba5d8ffbf2ce1944331ff7294a0ec7c03
SwiftProtobuf: 6ef3f0e422ef90d6605ca20b21a94f6c1324d6b3 SwiftProtobuf: 6ef3f0e422ef90d6605ca20b21a94f6c1324d6b3
SwiftyGif: 6c3eafd0ce693cad58bb63d2b2fb9bacb8552780 SwiftyGif: 6c3eafd0ce693cad58bb63d2b2fb9bacb8552780

View file

@ -3,6 +3,12 @@ import 'wallets/crypto_currency/intermediate/frost_currency.dart';
part 'app_config.g.dart'; part 'app_config.g.dart';
enum AppFeature {
themeSelection,
buy,
swap;
}
abstract class AppConfig { abstract class AppConfig {
static const appName = _prefix + _separator + suffix; static const appName = _prefix + _separator + suffix;
@ -12,6 +18,8 @@ abstract class AppConfig {
static String get appDefaultDataDirName => _appDataDirName; static String get appDefaultDataDirName => _appDataDirName;
static String get commitHash => _commitHash; static String get commitHash => _commitHash;
static bool hasFeature(AppFeature feature) => _features.contains(feature);
static ({String light, String dark})? get appIconAsset => _appIconAsset; static ({String light, String dark})? get appIconAsset => _appIconAsset;
static List<CryptoCurrency> get coins => _supportedCoins; static List<CryptoCurrency> get coins => _supportedCoins;

View file

@ -422,6 +422,20 @@ class DbVersionMigrator with WalletDB {
// try to continue migrating // try to continue migrating
return await migrate(12, secureStore: secureStore); return await migrate(12, secureStore: secureStore);
case 12:
// migrate
await _v12(secureStore);
// update version
await DB.instance.put<dynamic>(
boxName: DB.boxNameDBInfo,
key: "hive_data_version",
value: 13,
);
// try to continue migrating
return await migrate(13, secureStore: secureStore);
default: default:
// finally return // finally return
return; return;
@ -701,4 +715,15 @@ class DbVersionMigrator with WalletDB {
Future<void> _v11(SecureStorageInterface secureStore) async { Future<void> _v11(SecureStorageInterface secureStore) async {
await migrateWalletsToIsar(secureStore: secureStore); await migrateWalletsToIsar(secureStore: secureStore);
} }
Future<void> _v12(SecureStorageInterface secureStore) async {
for (final identifier in ["firo", "firoTestNet"]) {
await DB.instance.deleteBoxFromDisk(
boxName: "${identifier}_anonymitySetSparkCache",
);
await DB.instance.deleteBoxFromDisk(
boxName: "${identifier}_sparkUsedCoinsTagsCache",
);
}
}
} }

View file

@ -13,6 +13,7 @@ import 'dart:isolate';
import 'package:cw_core/wallet_info.dart' as xmr; import 'package:cw_core/wallet_info.dart' as xmr;
import 'package:hive/hive.dart'; import 'package:hive/hive.dart';
import 'package:mutex/mutex.dart'; import 'package:mutex/mutex.dart';
import '../../app_config.dart'; import '../../app_config.dart';
import '../../models/exchange/response_objects/trade.dart'; import '../../models/exchange/response_objects/trade.dart';
import '../../models/node_model.dart'; import '../../models/node_model.dart';
@ -55,12 +56,8 @@ class DB {
// firo only // firo only
String _boxNameSetCache({required CryptoCurrency currency}) => String _boxNameSetCache({required CryptoCurrency currency}) =>
"${currency.identifier}_anonymitySetCache"; "${currency.identifier}_anonymitySetCache";
String _boxNameSetSparkCache({required CryptoCurrency currency}) =>
"${currency.identifier}_anonymitySetSparkCache";
String _boxNameUsedSerialsCache({required CryptoCurrency currency}) => String _boxNameUsedSerialsCache({required CryptoCurrency currency}) =>
"${currency.identifier}_usedSerialsCache"; "${currency.identifier}_usedSerialsCache";
String _boxNameSparkUsedCoinsTagsCache({required CryptoCurrency currency}) =>
"${currency.identifier}_sparkUsedCoinsTagsCache";
Box<NodeModel>? _boxNodeModels; Box<NodeModel>? _boxNodeModels;
Box<NodeModel>? _boxPrimaryNodes; Box<NodeModel>? _boxPrimaryNodes;
@ -81,7 +78,6 @@ class DB {
final Map<String, Box<dynamic>> _txCacheBoxes = {}; final Map<String, Box<dynamic>> _txCacheBoxes = {};
final Map<String, Box<dynamic>> _setCacheBoxes = {}; final Map<String, Box<dynamic>> _setCacheBoxes = {};
final Map<String, Box<dynamic>> _setSparkCacheBoxes = {};
final Map<String, Box<dynamic>> _usedSerialsCacheBoxes = {}; final Map<String, Box<dynamic>> _usedSerialsCacheBoxes = {};
final Map<String, Box<dynamic>> _getSparkUsedCoinsTagsCacheBoxes = {}; final Map<String, Box<dynamic>> _getSparkUsedCoinsTagsCacheBoxes = {};
@ -213,16 +209,6 @@ class DB {
await Hive.openBox<dynamic>(_boxNameSetCache(currency: currency)); await Hive.openBox<dynamic>(_boxNameSetCache(currency: currency));
} }
Future<Box<dynamic>> getSparkAnonymitySetCacheBox({
required CryptoCurrency currency,
}) async {
if (_setSparkCacheBoxes[currency.identifier]?.isOpen != true) {
_setSparkCacheBoxes.remove(currency.identifier);
}
return _setSparkCacheBoxes[currency.identifier] ??=
await Hive.openBox<dynamic>(_boxNameSetSparkCache(currency: currency));
}
Future<void> closeAnonymitySetCacheBox({ Future<void> closeAnonymitySetCacheBox({
required CryptoCurrency currency, required CryptoCurrency currency,
}) async { }) async {
@ -241,18 +227,6 @@ class DB {
); );
} }
Future<Box<dynamic>> getSparkUsedCoinsTagsCacheBox({
required CryptoCurrency currency,
}) async {
if (_getSparkUsedCoinsTagsCacheBoxes[currency.identifier]?.isOpen != true) {
_getSparkUsedCoinsTagsCacheBoxes.remove(currency.identifier);
}
return _getSparkUsedCoinsTagsCacheBoxes[currency.identifier] ??=
await Hive.openBox<dynamic>(
_boxNameSparkUsedCoinsTagsCache(currency: currency),
);
}
Future<void> closeUsedSerialsCacheBox({ Future<void> closeUsedSerialsCacheBox({
required CryptoCurrency currency, required CryptoCurrency currency,
}) async { }) async {
@ -266,15 +240,9 @@ class DB {
await deleteAll<dynamic>(boxName: _boxNameTxCache(currency: currency)); await deleteAll<dynamic>(boxName: _boxNameTxCache(currency: currency));
if (currency is Firo) { if (currency is Firo) {
await deleteAll<dynamic>(boxName: _boxNameSetCache(currency: currency)); await deleteAll<dynamic>(boxName: _boxNameSetCache(currency: currency));
await deleteAll<dynamic>(
boxName: _boxNameSetSparkCache(currency: currency),
);
await deleteAll<dynamic>( await deleteAll<dynamic>(
boxName: _boxNameUsedSerialsCache(currency: currency), boxName: _boxNameUsedSerialsCache(currency: currency),
); );
await deleteAll<dynamic>(
boxName: _boxNameSparkUsedCoinsTagsCache(currency: currency),
);
} }
} }

View file

@ -11,6 +11,8 @@
import 'package:decimal/decimal.dart'; import 'package:decimal/decimal.dart';
import 'package:flutter_native_splash/cli_commands.dart'; import 'package:flutter_native_splash/cli_commands.dart';
import 'package:isar/isar.dart'; import 'package:isar/isar.dart';
import 'package:tuple/tuple.dart';
import '../../exceptions/main_db/main_db_exception.dart'; import '../../exceptions/main_db/main_db_exception.dart';
import '../../models/isar/models/block_explorer.dart'; import '../../models/isar/models/block_explorer.dart';
import '../../models/isar/models/blockchain_data/v2/transaction_v2.dart'; import '../../models/isar/models/blockchain_data/v2/transaction_v2.dart';
@ -26,7 +28,6 @@ import '../../wallets/isar/models/spark_coin.dart';
import '../../wallets/isar/models/token_wallet_info.dart'; import '../../wallets/isar/models/token_wallet_info.dart';
import '../../wallets/isar/models/wallet_info.dart'; import '../../wallets/isar/models/wallet_info.dart';
import '../../wallets/isar/models/wallet_info_meta.dart'; import '../../wallets/isar/models/wallet_info_meta.dart';
import 'package:tuple/tuple.dart';
part '../queries/queries.dart'; part '../queries/queries.dart';
@ -149,8 +150,9 @@ class MainDB {
} }
// tx block explorers // tx block explorers
TransactionBlockExplorer? getTransactionBlockExplorer( TransactionBlockExplorer? getTransactionBlockExplorer({
{required CryptoCurrency cryptoCurrency}) { required CryptoCurrency cryptoCurrency,
}) {
return isar.transactionBlockExplorers return isar.transactionBlockExplorers
.where() .where()
.tickerEqualTo(cryptoCurrency.ticker) .tickerEqualTo(cryptoCurrency.ticker)

View file

@ -207,7 +207,8 @@ Future<void> migrateWalletsToIsar({
} }
await _cleanupOnSuccess( await _cleanupOnSuccess(
walletIds: newInfo.map((e) => e.$1.walletId).toList()); walletIds: newInfo.map((e) => e.$1.walletId).toList(),
);
} }
Future<void> _cleanupOnSuccess({required List<String> walletIds}) async { Future<void> _cleanupOnSuccess({required List<String> walletIds}) async {

View file

@ -0,0 +1,164 @@
import 'dart:async';
import 'dart:io';
import 'dart:isolate';
import 'package:flutter/foundation.dart';
import 'package:flutter_libsparkmobile/flutter_libsparkmobile.dart';
import 'package:mutex/mutex.dart';
import 'package:sqlite3/sqlite3.dart';
import 'package:uuid/uuid.dart';
import '../../electrumx_rpc/electrumx_client.dart';
import '../../utilities/extensions/extensions.dart';
import '../../utilities/logger.dart';
import '../../utilities/stack_file_system.dart';
part 'firo_cache_coordinator.dart';
part 'firo_cache_reader.dart';
part 'firo_cache_worker.dart';
part 'firo_cache_writer.dart';
/// Temporary debugging log function for this file
void _debugLog(Object? object) {
if (kDebugMode) {
Logging.instance.log(
object,
level: LogLevel.Debug,
);
}
}
abstract class _FiroCache {
static const int _setCacheVersion = 1;
static const int _tagsCacheVersion = 1;
static const String sparkSetCacheFileName =
"spark_set_v$_setCacheVersion.sqlite3";
static const String sparkUsedTagsCacheFileName =
"spark_tags_v$_tagsCacheVersion.sqlite3";
static Database? _setCacheDB;
static Database? _usedTagsCacheDB;
static Database get setCacheDB {
if (_setCacheDB == null) {
throw Exception(
"FiroCache.init() must be called before accessing FiroCache.db!",
);
}
return _setCacheDB!;
}
static Database get usedTagsCacheDB {
if (_usedTagsCacheDB == null) {
throw Exception(
"FiroCache.init() must be called before accessing FiroCache.db!",
);
}
return _usedTagsCacheDB!;
}
static Future<void>? _initFuture;
static Future<void> init() => _initFuture ??= _init();
static Future<void> _init() async {
final sqliteDir =
await StackFileSystem.applicationFiroCacheSQLiteDirectory();
final sparkSetCacheFile = File("${sqliteDir.path}/$sparkSetCacheFileName");
final sparkUsedTagsCacheFile =
File("${sqliteDir.path}/$sparkUsedTagsCacheFileName");
if (!(await sparkSetCacheFile.exists())) {
await _createSparkSetCacheDb(sparkSetCacheFile.path);
}
if (!(await sparkUsedTagsCacheFile.exists())) {
await _createSparkUsedTagsCacheDb(sparkUsedTagsCacheFile.path);
}
_setCacheDB = sqlite3.open(
sparkSetCacheFile.path,
mode: OpenMode.readWrite,
);
_usedTagsCacheDB = sqlite3.open(
sparkUsedTagsCacheFile.path,
mode: OpenMode.readWrite,
);
}
static Future<void> _deleteAllCache() async {
final start = DateTime.now();
setCacheDB.execute(
"""
DELETE FROM SparkSet;
DELETE FROM SparkCoin;
DELETE FROM SparkSetCoins;
VACUUM;
""",
);
usedTagsCacheDB.execute(
"""
DELETE FROM SparkUsedCoinTags;
VACUUM;
""",
);
_debugLog(
"_deleteAllCache() "
"duration = ${DateTime.now().difference(start)}",
);
}
static Future<void> _createSparkSetCacheDb(String file) async {
final db = sqlite3.open(
file,
mode: OpenMode.readWriteCreate,
);
db.execute(
"""
CREATE TABLE SparkSet (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
blockHash TEXT NOT NULL,
setHash TEXT NOT NULL,
groupId INTEGER NOT NULL,
timestampUTC INTEGER NOT NULL,
UNIQUE (blockHash, setHash, groupId)
);
CREATE TABLE SparkCoin (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
serialized TEXT NOT NULL,
txHash TEXT NOT NULL,
context TEXT NOT NULL,
UNIQUE(serialized, txHash, context)
);
CREATE TABLE SparkSetCoins (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
setId INTEGER NOT NULL,
coinId INTEGER NOT NULL,
FOREIGN KEY (setId) REFERENCES SparkSet(id),
FOREIGN KEY (coinId) REFERENCES SparkCoin(id)
);
""",
);
db.dispose();
}
static Future<void> _createSparkUsedTagsCacheDb(String file) async {
final db = sqlite3.open(
file,
mode: OpenMode.readWriteCreate,
);
db.execute(
"""
CREATE TABLE SparkUsedCoinTags (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,
tag TEXT NOT NULL UNIQUE
);
""",
);
db.dispose();
}
}

View file

@ -0,0 +1,166 @@
part of 'firo_cache.dart';
/// Wrapper class for [_FiroCache] as [_FiroCache] should eventually be handled in a
/// background isolate and [FiroCacheCoordinator] should manage that isolate
abstract class FiroCacheCoordinator {
static _FiroCacheWorker? _worker;
static bool _init = false;
static Future<void> init() async {
if (_init) {
return;
}
_init = true;
await _FiroCache.init();
_worker = await _FiroCacheWorker.spawn();
}
static Future<void> clearSharedCache() async {
return await _FiroCache._deleteAllCache();
}
static Future<String> getSparkCacheSize() async {
final dir = await StackFileSystem.applicationFiroCacheSQLiteDirectory();
final setCacheFile = File(
"${dir.path}/${_FiroCache.sparkSetCacheFileName}",
);
final usedTagsCacheFile = File(
"${dir.path}/${_FiroCache.sparkUsedTagsCacheFileName}",
);
final int bytes =
((await setCacheFile.exists()) ? await setCacheFile.length() : 0) +
((await usedTagsCacheFile.exists())
? await usedTagsCacheFile.length()
: 0);
if (bytes < 1024) {
return '$bytes B';
} else if (bytes < 1048576) {
final double kbSize = bytes / 1024;
return '${kbSize.toStringAsFixed(2)} KB';
} else if (bytes < 1073741824) {
final double mbSize = bytes / 1048576;
return '${mbSize.toStringAsFixed(2)} MB';
} else {
final double gbSize = bytes / 1073741824;
return '${gbSize.toStringAsFixed(2)} GB';
}
}
static Future<void> runFetchAndUpdateSparkUsedCoinTags(
ElectrumXClient client,
) async {
final count = await FiroCacheCoordinator.getUsedCoinTagsLastAddedRowId();
final unhashedTags = await client.getSparkUnhashedUsedCoinsTags(
startNumber: count,
);
if (unhashedTags.isNotEmpty) {
await _worker!.runTask(
FCTask(
func: FCFuncName._updateSparkUsedTagsWith,
data: unhashedTags,
),
);
}
}
static Future<void> runFetchAndUpdateSparkAnonSetCacheForGroupId(
int groupId,
ElectrumXClient client,
) async {
final blockhashResult =
await FiroCacheCoordinator.getLatestSetInfoForGroupId(
groupId,
);
final blockHash = blockhashResult?.blockHash ?? "";
final json = await client.getSparkAnonymitySet(
coinGroupId: groupId.toString(),
startBlockHash: blockHash.toHexReversedFromBase64,
);
await _worker!.runTask(
FCTask(
func: FCFuncName._updateSparkAnonSetCoinsWith,
data: (groupId, json),
),
);
}
// ===========================================================================
static Future<Set<String>> getUsedCoinTags(int startNumber) async {
final result = await _Reader._getSparkUsedCoinTags(
startNumber,
db: _FiroCache.usedTagsCacheDB,
);
return result.map((e) => e["tag"] as String).toSet();
}
/// This should be the equivalent of counting the number of tags in the db.
/// Assuming the integrity of the data. Faster than actually calling count on
/// a table where no records have been deleted. None should be deleted from
/// this table in practice.
static Future<int> getUsedCoinTagsLastAddedRowId() async {
final result = await _Reader._getUsedCoinTagsLastAddedRowId(
db: _FiroCache.usedTagsCacheDB,
);
if (result.isEmpty) {
return 0;
}
return result.first["highestId"] as int? ?? 0;
}
static Future<bool> checkTagIsUsed(
String tag,
) async {
return await _Reader._checkTagIsUsed(
tag,
db: _FiroCache.usedTagsCacheDB,
);
}
static Future<ResultSet> getSetCoinsForGroupId(
int groupId, {
int? newerThanTimeStamp,
}) async {
return await _Reader._getSetCoinsForGroupId(
groupId,
db: _FiroCache.setCacheDB,
newerThanTimeStamp: newerThanTimeStamp,
);
}
static Future<
({
String blockHash,
String setHash,
int timestampUTC,
})?> getLatestSetInfoForGroupId(
int groupId,
) async {
final result = await _Reader._getLatestSetInfoForGroupId(
groupId,
db: _FiroCache.setCacheDB,
);
if (result.isEmpty) {
return null;
}
return (
blockHash: result.first["blockHash"] as String,
setHash: result.first["setHash"] as String,
timestampUTC: result.first["timestampUTC"] as int,
);
}
static Future<bool> checkSetInfoForGroupIdExists(
int groupId,
) async {
return await _Reader._checkSetInfoForGroupIdExists(
groupId,
db: _FiroCache.setCacheDB,
);
}
}

View file

@ -0,0 +1,103 @@
part of 'firo_cache.dart';
/// Keep all fetch queries in this separate file
abstract class _Reader {
// ===========================================================================
// =============== Spark anonymity set queries ===============================
static Future<ResultSet> _getSetCoinsForGroupId(
int groupId, {
required Database db,
int? newerThanTimeStamp,
}) async {
String query = """
SELECT sc.serialized, sc.txHash, sc.context
FROM SparkSet AS ss
JOIN SparkSetCoins AS ssc ON ss.id = ssc.setId
JOIN SparkCoin AS sc ON ssc.coinId = sc.id
WHERE ss.groupId = $groupId
""";
if (newerThanTimeStamp != null) {
query += " AND ss.timestampUTC"
" > $newerThanTimeStamp";
}
return db.select("$query;");
}
static Future<ResultSet> _getLatestSetInfoForGroupId(
int groupId, {
required Database db,
}) async {
final query = """
SELECT ss.blockHash, ss.setHash, ss.timestampUTC
FROM SparkSet ss
WHERE ss.groupId = $groupId
ORDER BY ss.timestampUTC DESC
LIMIT 1;
""";
return db.select("$query;");
}
static Future<bool> _checkSetInfoForGroupIdExists(
int groupId, {
required Database db,
}) async {
final query = """
SELECT EXISTS (
SELECT 1
FROM SparkSet
WHERE groupId = $groupId
) AS setExists;
""";
return db.select("$query;").first["setExists"] == 1;
}
// ===========================================================================
// =============== Spark used coin tags queries ==============================
static Future<ResultSet> _getSparkUsedCoinTags(
int startNumber, {
required Database db,
}) async {
String query = """
SELECT tag
FROM SparkUsedCoinTags
""";
if (startNumber > 0) {
query += " WHERE id >= $startNumber";
}
return db.select("$query;");
}
static Future<ResultSet> _getUsedCoinTagsLastAddedRowId({
required Database db,
}) async {
const query = """
SELECT MAX(id) AS highestId
FROM SparkUsedCoinTags;
""";
return db.select("$query;");
}
static Future<bool> _checkTagIsUsed(
String tag, {
required Database db,
}) async {
final query = """
SELECT EXISTS (
SELECT 1
FROM SparkUsedCoinTags
WHERE tag = '$tag'
) AS tagExists;
""";
return db.select("$query;").first["tagExists"] == 1;
}
}

View file

@ -0,0 +1,140 @@
part of 'firo_cache.dart';
enum FCFuncName {
_updateSparkAnonSetCoinsWith,
_updateSparkUsedTagsWith,
}
class FCTask {
final id = const Uuid().v4();
final FCFuncName func;
final dynamic data;
FCTask({required this.func, required this.data});
}
class _FiroCacheWorker {
final SendPort _commands;
final ReceivePort _responses;
final Map<String, Completer<Object?>> _activeRequests = {};
Future<Object?> runTask(FCTask task) async {
final completer = Completer<Object?>.sync();
_activeRequests[task.id] = completer;
_commands.send(task);
return await completer.future;
}
static Future<_FiroCacheWorker> spawn() async {
final dir = await StackFileSystem.applicationFiroCacheSQLiteDirectory();
final setCacheFilePath = "${dir.path}/${_FiroCache.sparkSetCacheFileName}";
final usedTagsCacheFilePath =
"${dir.path}/${_FiroCache.sparkUsedTagsCacheFileName}";
final initPort = RawReceivePort();
final connection = Completer<(ReceivePort, SendPort)>.sync();
initPort.handler = (dynamic initialMessage) {
final commandPort = initialMessage as SendPort;
connection.complete(
(
ReceivePort.fromRawReceivePort(initPort),
commandPort,
),
);
};
try {
await Isolate.spawn(
_startWorkerIsolate,
(initPort.sendPort, setCacheFilePath, usedTagsCacheFilePath),
);
} catch (_) {
initPort.close();
rethrow;
}
final (receivePort, sendPort) = await connection.future;
return _FiroCacheWorker._(receivePort, sendPort);
}
_FiroCacheWorker._(this._responses, this._commands) {
_responses.listen(_handleResponsesFromIsolate);
}
void _handleResponsesFromIsolate(dynamic message) {
final (id, error) = message as (String, Object?);
final completer = _activeRequests.remove(id)!;
if (error != null) {
completer.completeError(error);
} else {
completer.complete(id);
}
}
static void _handleCommandsToIsolate(
ReceivePort receivePort,
SendPort sendPort,
Database setCacheDb,
Database usedTagsCacheDb,
Mutex mutex,
) {
receivePort.listen((message) {
final task = message as FCTask;
mutex.protect(() async {
try {
final FCResult result;
switch (task.func) {
case FCFuncName._updateSparkAnonSetCoinsWith:
final data = task.data as (int, Map<String, dynamic>);
result = _updateSparkAnonSetCoinsWith(
setCacheDb,
data.$2,
data.$1,
);
break;
case FCFuncName._updateSparkUsedTagsWith:
result = _updateSparkUsedTagsWith(
usedTagsCacheDb,
task.data as List<String>,
);
break;
}
if (result.success) {
sendPort.send((task.id, null));
} else {
sendPort.send((task.id, result.error!));
}
} catch (e) {
sendPort.send((task.id, e));
}
});
});
}
static void _startWorkerIsolate((SendPort, String, String) args) {
final receivePort = ReceivePort();
args.$1.send(receivePort.sendPort);
final mutex = Mutex();
final setCacheDb = sqlite3.open(
args.$2,
mode: OpenMode.readWrite,
);
final usedTagsCacheDb = sqlite3.open(
args.$3,
mode: OpenMode.readWrite,
);
_handleCommandsToIsolate(
receivePort,
args.$1,
setCacheDb,
usedTagsCacheDb,
mutex,
);
}
}

View file

@ -0,0 +1,169 @@
part of 'firo_cache.dart';
class FCResult {
final bool success;
final Object? error;
FCResult({required this.success, this.error});
}
// ===========================================================================
// ================== write to spark used tags cache =========================
/// update the sqlite cache
/// Expected json format:
/// returns true if successful, otherwise some exception
FCResult _updateSparkUsedTagsWith(
Database db,
List<String> tags,
) {
// hash the tags here since this function is called in a background isolate
final hashedTags = LibSpark.hashTags(base64Tags: tags);
if (hashedTags.isEmpty) {
// nothing to add, return early
return FCResult(success: true);
}
db.execute("BEGIN;");
try {
for (final tag in hashedTags) {
db.execute(
"""
INSERT OR IGNORE INTO SparkUsedCoinTags (tag)
VALUES (?);
""",
[tag],
);
}
db.execute("COMMIT;");
return FCResult(success: true);
} catch (e) {
db.execute("ROLLBACK;");
return FCResult(success: false, error: e);
}
}
// ===========================================================================
// ================== write to spark anon set cache ==========================
/// update the sqlite cache
/// Expected json format:
/// {
/// "blockHash": "someBlockHash",
/// "setHash": "someSetHash",
/// "coins": [
/// ["serliazed1", "hash1", "context1"],
/// ["serliazed2", "hash2", "context2"],
/// ...
/// ["serliazed3", "hash3", "context3"],
/// ["serliazed4", "hash4", "context4"],
/// ],
/// }
///
/// returns true if successful, otherwise false
FCResult _updateSparkAnonSetCoinsWith(
Database db,
Map<String, dynamic> json,
int groupId,
) {
final blockHash = json["blockHash"] as String;
final setHash = json["setHash"] as String;
final coinsRaw = json["coins"] as List;
if (coinsRaw.isEmpty) {
// no coins to actually insert
return FCResult(success: true);
}
final checkResult = db.select(
"""
SELECT *
FROM SparkSet
WHERE blockHash = ? AND setHash = ? AND groupId = ?;
""",
[
blockHash,
setHash,
groupId,
],
);
if (checkResult.isNotEmpty) {
// already up to date
return FCResult(success: true);
}
final coins = coinsRaw
.map(
(e) => [
e[0] as String,
e[1] as String,
e[2] as String,
],
)
.toList();
final timestamp = DateTime.now().toUtc().millisecondsSinceEpoch ~/ 1000;
db.execute("BEGIN;");
try {
db.execute(
"""
INSERT INTO SparkSet (blockHash, setHash, groupId, timestampUTC)
VALUES (?, ?, ?, ?);
""",
[blockHash, setHash, groupId, timestamp],
);
final setId = db.lastInsertRowId;
for (final coin in coins) {
int coinId;
try {
// try to insert and get row id
db.execute(
"""
INSERT INTO SparkCoin (serialized, txHash, context)
VALUES (?, ?, ?);
""",
coin,
);
coinId = db.lastInsertRowId;
} on SqliteException catch (e) {
// if there already is a matching coin in the db
// just grab its row id
if (e.extendedResultCode == 2067) {
final result = db.select(
"""
SELECT id
FROM SparkCoin
WHERE serialized = ? AND txHash = ? AND context = ?;
""",
coin,
);
coinId = result.first["id"] as int;
} else {
rethrow;
}
}
// finally add the row id to the newly added set
db.execute(
"""
INSERT INTO SparkSetCoins (setId, coinId)
VALUES (?, ?);
""",
[setId, coinId],
);
}
db.execute("COMMIT;");
return FCResult(success: true);
} catch (e) {
db.execute("ROLLBACK;");
return FCResult(success: false, error: e);
}
}

View file

@ -11,7 +11,6 @@
import 'dart:convert'; import 'dart:convert';
import '../../utilities/amount/amount.dart'; import '../../utilities/amount/amount.dart';
import '../../wallets/crypto_currency/coins/ethereum.dart';
import '../../wallets/crypto_currency/crypto_currency.dart'; import '../../wallets/crypto_currency/crypto_currency.dart';
class EthTokenTxExtraDTO { class EthTokenTxExtraDTO {

View file

@ -11,7 +11,6 @@
import 'dart:convert'; import 'dart:convert';
import '../../utilities/amount/amount.dart'; import '../../utilities/amount/amount.dart';
import '../../wallets/crypto_currency/coins/ethereum.dart';
import '../../wallets/crypto_currency/crypto_currency.dart'; import '../../wallets/crypto_currency/crypto_currency.dart';
class EthTxDTO { class EthTxDTO {

View file

@ -1,7 +1,8 @@
import 'litescribe_response.dart';
import 'inscription_data.dart'; import 'inscription_data.dart';
import 'litescribe_response.dart';
class AddressInscriptionResponse extends LitescribeResponse<AddressInscriptionResponse> { class AddressInscriptionResponse
extends LitescribeResponse<AddressInscriptionResponse> {
final int status; final int status;
final String message; final String message;
final AddressInscriptionResult result; final AddressInscriptionResult result;
@ -16,7 +17,8 @@ class AddressInscriptionResponse extends LitescribeResponse<AddressInscriptionRe
return AddressInscriptionResponse( return AddressInscriptionResponse(
status: json['status'] as int, status: json['status'] as int,
message: json['message'] as String, message: json['message'] as String,
result: AddressInscriptionResult.fromJson(json['result'] as Map<String, dynamic>), result: AddressInscriptionResult.fromJson(
json['result'] as Map<String, dynamic>),
); );
} }
} }
@ -32,7 +34,9 @@ class AddressInscriptionResult {
factory AddressInscriptionResult.fromJson(Map<String, dynamic> json) { factory AddressInscriptionResult.fromJson(Map<String, dynamic> json) {
return AddressInscriptionResult( return AddressInscriptionResult(
list: (json['list'] as List).map((item) => InscriptionData.fromJson(item as Map<String, dynamic>)).toList(), list: (json['list'] as List)
.map((item) => InscriptionData.fromJson(item as Map<String, dynamic>))
.toList(),
total: json['total'] as int, total: json['total'] as int,
); );
} }

View file

@ -11,11 +11,12 @@
import 'dart:convert'; import 'dart:convert';
import 'dart:math'; import 'dart:math';
import 'package:string_validator/string_validator.dart';
import '../db/hive/db.dart'; import '../db/hive/db.dart';
import 'electrumx_client.dart';
import '../utilities/logger.dart'; import '../utilities/logger.dart';
import '../wallets/crypto_currency/crypto_currency.dart'; import '../wallets/crypto_currency/crypto_currency.dart';
import 'package:string_validator/string_validator.dart'; import 'electrumx_client.dart';
class CachedElectrumXClient { class CachedElectrumXClient {
final ElectrumXClient electrumXClient; final ElectrumXClient electrumXClient;
@ -115,70 +116,6 @@ class CachedElectrumXClient {
} }
} }
Future<Map<String, dynamic>> getSparkAnonymitySet({
required String groupId,
String blockhash = "",
required CryptoCurrency cryptoCurrency,
required bool useOnlyCacheIfNotEmpty,
}) async {
try {
final box = await DB.instance.getSparkAnonymitySetCacheBox(
currency: cryptoCurrency,
);
final cachedSet = box.get(groupId) as Map?;
Map<String, dynamic> set;
// null check to see if there is a cached set
if (cachedSet == null) {
set = {
"coinGroupID": int.parse(groupId),
"blockHash": blockhash,
"setHash": "",
"coins": <dynamic>[],
};
} else {
set = Map<String, dynamic>.from(cachedSet);
if (useOnlyCacheIfNotEmpty) {
return set;
}
}
final newSet = await electrumXClient.getSparkAnonymitySet(
coinGroupId: groupId,
startBlockHash: set["blockHash"] as String,
);
// update set with new data
if (newSet["setHash"] != "" && set["setHash"] != newSet["setHash"]) {
set["setHash"] = newSet["setHash"];
set["blockHash"] = newSet["blockHash"];
for (int i = (newSet["coins"] as List).length - 1; i >= 0; i--) {
// TODO verify this is correct (or append?)
if ((set["coins"] as List)
.where((e) => e[0] == newSet["coins"][i][0])
.isEmpty) {
set["coins"].insert(0, newSet["coins"][i]);
}
}
// save set to db
await box.put(groupId, set);
Logging.instance.log(
"Updated current anonymity set for ${cryptoCurrency.identifier} with group ID $groupId",
level: LogLevel.Info,
);
}
return set;
} catch (e, s) {
Logging.instance.log(
"Failed to process CachedElectrumX.getSparkAnonymitySet(): $e\n$s",
level: LogLevel.Error,
);
rethrow;
}
}
String base64ToHex(String source) => String base64ToHex(String source) =>
base64Decode(LineSplitter.split(source).join()) base64Decode(LineSplitter.split(source).join())
.map((e) => e.toRadixString(16).padLeft(2, '0')) .map((e) => e.toRadixString(16).padLeft(2, '0'))
@ -283,56 +220,10 @@ class CachedElectrumXClient {
} }
} }
Future<Set<String>> getSparkUsedCoinsTags({ /// Clear all cached transactions for the specified coin
Future<void> clearSharedTransactionCache({
required CryptoCurrency cryptoCurrency, required CryptoCurrency cryptoCurrency,
}) async { }) async {
try {
final box = await DB.instance.getSparkUsedCoinsTagsCacheBox(
currency: cryptoCurrency,
);
final _list = box.get("tags") as List?;
final Set<String> cachedTags =
_list == null ? {} : List<String>.from(_list).toSet();
final startNumber = max(
0,
cachedTags.length - 100, // 100 being some arbitrary buffer
);
final newTags = await electrumXClient.getSparkUsedCoinsTags(
startNumber: startNumber,
);
// ensure we are getting some overlap so we know we are not missing any
if (cachedTags.isNotEmpty && newTags.isNotEmpty) {
assert(cachedTags.intersection(newTags).isNotEmpty);
}
// Make newTags an Iterable<String>.
final Iterable<String> iterableTags = newTags.map((e) => e.toString());
cachedTags.addAll(iterableTags);
await box.put(
"tags",
cachedTags.toList(),
);
return cachedTags;
} catch (e, s) {
Logging.instance.log(
"Failed to process CachedElectrumX.getSparkUsedCoinsTags(): $e\n$s",
level: LogLevel.Error,
);
rethrow;
}
}
/// Clear all cached transactions for the specified coin
Future<void> clearSharedTransactionCache(
{required CryptoCurrency cryptoCurrency}) async {
await DB.instance.clearSharedTransactionCache(currency: cryptoCurrency); await DB.instance.clearSharedTransactionCache(currency: cryptoCurrency);
await DB.instance.closeAnonymitySetCacheBox(currency: cryptoCurrency); await DB.instance.closeAnonymitySetCacheBox(currency: cryptoCurrency);
} }

View file

@ -17,10 +17,9 @@ import 'package:electrum_adapter/electrum_adapter.dart' as electrum_adapter;
import 'package:electrum_adapter/electrum_adapter.dart'; import 'package:electrum_adapter/electrum_adapter.dart';
import 'package:electrum_adapter/methods/specific/firo.dart'; import 'package:electrum_adapter/methods/specific/firo.dart';
import 'package:event_bus/event_bus.dart'; import 'package:event_bus/event_bus.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter_libsparkmobile/flutter_libsparkmobile.dart';
import 'package:mutex/mutex.dart'; import 'package:mutex/mutex.dart';
import 'client_manager.dart'; import 'package:stream_channel/stream_channel.dart';
import '../exceptions/electrumx/no_such_transaction.dart'; import '../exceptions/electrumx/no_such_transaction.dart';
import '../services/event_bus/events/global/tor_connection_status_changed_event.dart'; import '../services/event_bus/events/global/tor_connection_status_changed_event.dart';
import '../services/event_bus/events/global/tor_status_changed_event.dart'; import '../services/event_bus/events/global/tor_status_changed_event.dart';
@ -28,10 +27,8 @@ import '../services/event_bus/global_event_bus.dart';
import '../services/tor_service.dart'; import '../services/tor_service.dart';
import '../utilities/logger.dart'; import '../utilities/logger.dart';
import '../utilities/prefs.dart'; import '../utilities/prefs.dart';
import '../wallets/crypto_currency/coins/dogecoin.dart';
import '../wallets/crypto_currency/coins/firo.dart';
import '../wallets/crypto_currency/crypto_currency.dart'; import '../wallets/crypto_currency/crypto_currency.dart';
import 'package:stream_channel/stream_channel.dart'; import 'client_manager.dart';
class WifiOnlyException implements Exception {} class WifiOnlyException implements Exception {}
@ -912,10 +909,7 @@ class ElectrumXClient {
String? requestID, String? requestID,
}) async { }) async {
try { try {
Logging.instance.log( final start = DateTime.now();
"attempting to fetch spark.getsparkanonymityset...",
level: LogLevel.Info,
);
await _checkElectrumAdapter(); await _checkElectrumAdapter();
final Map<String, dynamic> response = final Map<String, dynamic> response =
await (getElectrumAdapter() as FiroElectrumClient) await (getElectrumAdapter() as FiroElectrumClient)
@ -924,7 +918,10 @@ class ElectrumXClient {
startBlockHash: startBlockHash, startBlockHash: startBlockHash,
); );
Logging.instance.log( Logging.instance.log(
"Fetching spark.getsparkanonymityset finished", "Finished ElectrumXClient.getSparkAnonymitySet(coinGroupId"
"=$coinGroupId, startBlockHash=$startBlockHash). "
"coins.length: ${(response["coins"] as List?)?.length}"
"Duration=${DateTime.now().difference(start)}",
level: LogLevel.Info, level: LogLevel.Info,
); );
return response; return response;
@ -933,18 +930,15 @@ class ElectrumXClient {
} }
} }
// TODO: update when we get new call to include tx hashes in response
/// Takes [startNumber], if it is 0, we get the full set, /// Takes [startNumber], if it is 0, we get the full set,
/// otherwise the used tags after that number /// otherwise the used tags after that number
Future<Set<String>> getSparkUsedCoinsTags({ Future<List<String>> getSparkUnhashedUsedCoinsTags({
String? requestID, String? requestID,
required int startNumber, required int startNumber,
}) async { }) async {
try { try {
// Use electrum_adapter package's getSparkUsedCoinsTags method. final start = DateTime.now();
Logging.instance.log(
"attempting to fetch spark.getusedcoinstags...",
level: LogLevel.Info,
);
await _checkElectrumAdapter(); await _checkElectrumAdapter();
final Map<String, dynamic> response = final Map<String, dynamic> response =
await (getElectrumAdapter() as FiroElectrumClient) await (getElectrumAdapter() as FiroElectrumClient)
@ -956,8 +950,16 @@ class ElectrumXClient {
level: LogLevel.Info, level: LogLevel.Info,
); );
final map = Map<String, dynamic>.from(response); final map = Map<String, dynamic>.from(response);
final set = Set<String>.from(map["tags"] as List); final tags = List<String>.from(map["tags"] as List);
return await compute(_ffiHashTagsComputeWrapper, set);
Logging.instance.log(
"Finished ElectrumXClient.getSparkUnhashedUsedCoinsTags(startNumber"
"=$startNumber). "
"Duration=${DateTime.now().difference(start)}",
level: LogLevel.Info,
);
return tags;
} catch (e) { } catch (e) {
Logging.instance.log(e, level: LogLevel.Error); Logging.instance.log(e, level: LogLevel.Error);
rethrow; rethrow;
@ -1023,6 +1025,64 @@ class ElectrumXClient {
} }
} }
/// Returns the txids of the current transactions found in the mempool
Future<Set<String>> getMempoolTxids({
String? requestID,
}) async {
try {
final start = DateTime.now();
final response = await request(
requestID: requestID,
command: "spark.getmempooltxids",
);
// TODO verify once server is live
final txids = List<String>.from(response as List).toSet();
// final map = Map<String, dynamic>.from(response as Map);
// final txids = List<String>.from(map["tags"] as List).toSet();
Logging.instance.log(
"Finished ElectrumXClient.getMempoolTxids(). "
"Duration=${DateTime.now().difference(start)}",
level: LogLevel.Info,
);
return txids;
} catch (e) {
Logging.instance.log(e, level: LogLevel.Error);
rethrow;
}
}
/// Returns the txids of the current transactions found in the mempool
Future<Map<String, dynamic>> getMempoolSparkData({
String? requestID,
required List<String> txids,
}) async {
try {
final start = DateTime.now();
final response = await request(
requestID: requestID,
command: "spark.getmempooltxs",
args: txids,
);
// TODO verify once server is live
final map = Map<String, dynamic>.from(response as Map);
Logging.instance.log(
"Finished ElectrumXClient.getMempoolSparkData(txids: $txids). "
"Duration=${DateTime.now().difference(start)}",
level: LogLevel.Info,
);
return map;
} catch (e) {
Logging.instance.log(e, level: LogLevel.Error);
rethrow;
}
}
// =========================================================================== // ===========================================================================
/// Get the current fee rate. /// Get the current fee rate.
@ -1094,7 +1154,3 @@ class ElectrumXClient {
} }
} }
} }
Set<String> _ffiHashTagsComputeWrapper(Set<String> base64Tags) {
return LibSpark.hashTags(base64Tags: base64Tags);
}

View file

@ -35,6 +35,7 @@ import 'app_config.dart';
import 'db/db_version_migration.dart'; import 'db/db_version_migration.dart';
import 'db/hive/db.dart'; import 'db/hive/db.dart';
import 'db/isar/main_db.dart'; import 'db/isar/main_db.dart';
import 'db/sqlite/firo_cache.dart';
import 'models/exchange/change_now/exchange_transaction.dart'; import 'models/exchange/change_now/exchange_transaction.dart';
import 'models/exchange/change_now/exchange_transaction_status.dart'; import 'models/exchange/change_now/exchange_transaction_status.dart';
import 'models/exchange/response_objects/trade.dart'; import 'models/exchange/response_objects/trade.dart';
@ -180,7 +181,8 @@ void main(List<String> args) async {
Hive.registerAdapter(UnspentCoinsInfoAdapter()); Hive.registerAdapter(UnspentCoinsInfoAdapter());
await Hive.initFlutter( await Hive.initFlutter(
(await StackFileSystem.applicationHiveDirectory()).path); (await StackFileSystem.applicationHiveDirectory()).path,
);
await Hive.openBox<dynamic>(DB.boxNameDBInfo); await Hive.openBox<dynamic>(DB.boxNameDBInfo);
await Hive.openBox<dynamic>(DB.boxNamePrefs); await Hive.openBox<dynamic>(DB.boxNamePrefs);
@ -199,11 +201,14 @@ void main(List<String> args) async {
} }
await StackFileSystem.initThemesDir(); await StackFileSystem.initThemesDir();
await FiroCacheCoordinator.init();
// Desktop migrate handled elsewhere (currently desktop_login_view.dart) // Desktop migrate handled elsewhere (currently desktop_login_view.dart)
if (!Util.isDesktop) { if (!Util.isDesktop) {
int dbVersion = DB.instance.get<dynamic>( final int dbVersion = DB.instance.get<dynamic>(
boxName: DB.boxNameDBInfo, key: "hive_data_version") as int? ?? boxName: DB.boxNameDBInfo,
key: "hive_data_version",
) as int? ??
0; 0;
if (dbVersion < Constants.currentDataVersion) { if (dbVersion < Constants.currentDataVersion) {
try { try {
@ -215,18 +220,17 @@ void main(List<String> args) async {
), ),
); );
} catch (e, s) { } catch (e, s) {
Logging.instance.log("Cannot migrate mobile database\n$e $s", Logging.instance.log(
level: LogLevel.Error, printFullLength: true); "Cannot migrate mobile database\n$e $s",
level: LogLevel.Error,
printFullLength: true,
);
} }
} }
} }
if (!Platform.isWindows) { monero.onStartup();
monero.onStartup(); wownero.onStartup();
}
if (!Platform.isLinux && !Platform.isWindows) {
wownero.onStartup();
}
// SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, // SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual,
// overlays: [SystemUiOverlay.bottom]); // overlays: [SystemUiOverlay.bottom]);
@ -266,7 +270,7 @@ void main(List<String> args) async {
/// MyApp initialises relevant services with a MultiProvider /// MyApp initialises relevant services with a MultiProvider
class MyApp extends StatelessWidget { class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key); const MyApp({super.key});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -283,8 +287,8 @@ class MyApp extends StatelessWidget {
class MaterialAppWithTheme extends ConsumerStatefulWidget { class MaterialAppWithTheme extends ConsumerStatefulWidget {
const MaterialAppWithTheme({ const MaterialAppWithTheme({
Key? key, super.key,
}) : super(key: key); });
@override @override
ConsumerState<MaterialAppWithTheme> createState() => ConsumerState<MaterialAppWithTheme> createState() =>
@ -386,7 +390,8 @@ class _MaterialAppWithThemeState extends ConsumerState<MaterialAppWithTheme>
switch (ref.read(prefsChangeNotifierProvider).backupFrequencyType) { switch (ref.read(prefsChangeNotifierProvider).backupFrequencyType) {
case BackupFrequencyType.everyTenMinutes: case BackupFrequencyType.everyTenMinutes:
ref.read(autoSWBServiceProvider).startPeriodicBackupTimer( ref.read(autoSWBServiceProvider).startPeriodicBackupTimer(
duration: const Duration(minutes: 10)); duration: const Duration(minutes: 10),
);
break; break;
case BackupFrequencyType.everyAppStart: case BackupFrequencyType.everyAppStart:
unawaited(ref.read(autoSWBServiceProvider).doBackup()); unawaited(ref.read(autoSWBServiceProvider).doBackup());
@ -452,7 +457,8 @@ class _MaterialAppWithThemeState extends ConsumerState<MaterialAppWithTheme>
await loadingCompleter.future; await loadingCompleter.future;
await goToRestoreSWB( await goToRestoreSWB(
ref.read(openedFromSWBFileStringStateProvider.state).state!); ref.read(openedFromSWBFileStringStateProvider.state).state!,
);
ref.read(openedFromSWBFileStringStateProvider.state).state = null; ref.read(openedFromSWBFileStringStateProvider.state).state = null;
} }
// ref.read(shouldShowLockscreenOnResumeStateProvider.state).state = false; // ref.read(shouldShowLockscreenOnResumeStateProvider.state).state = false;
@ -515,7 +521,8 @@ class _MaterialAppWithThemeState extends ConsumerState<MaterialAppWithTheme>
if (ref.read(openedFromSWBFileStringStateProvider.state).state != if (ref.read(openedFromSWBFileStringStateProvider.state).state !=
null) { null) {
await goToRestoreSWB( await goToRestoreSWB(
ref.read(openedFromSWBFileStringStateProvider.state).state!); ref.read(openedFromSWBFileStringStateProvider.state).state!,
);
ref.read(openedFromSWBFileStringStateProvider.state).state = null; ref.read(openedFromSWBFileStringStateProvider.state).state = null;
} }
} }
@ -563,8 +570,9 @@ class _MaterialAppWithThemeState extends ConsumerState<MaterialAppWithTheme>
await resetOpenPath(); await resetOpenPath();
Logging.instance.log( Logging.instance.log(
"This is the .swb content from intent: ${ref.read(openedFromSWBFileStringStateProvider.state).state}", "This is the .swb content from intent: ${ref.read(openedFromSWBFileStringStateProvider.state).state}",
level: LogLevel.Info); level: LogLevel.Info,
);
} }
/// should only be called on android currently /// should only be called on android currently
@ -579,27 +587,31 @@ class _MaterialAppWithThemeState extends ConsumerState<MaterialAppWithTheme>
.then((value) { .then((value) {
if (value is! bool || value == false) { if (value is! bool || value == false) {
Navigator.of(navigatorKey.currentContext!).pushNamed( Navigator.of(navigatorKey.currentContext!).pushNamed(
RestoreFromEncryptedStringView.routeName, RestoreFromEncryptedStringView.routeName,
arguments: encrypted); arguments: encrypted,
);
} }
}); });
} else { } else {
unawaited(Navigator.push( unawaited(
navigatorKey.currentContext!, Navigator.push(
RouteGenerator.getRoute( navigatorKey.currentContext!,
shouldUseMaterialRoute: RouteGenerator.useMaterialPageRoute, RouteGenerator.getRoute(
builder: (_) => LockscreenView( shouldUseMaterialRoute: RouteGenerator.useMaterialPageRoute,
showBackButton: true, builder: (_) => LockscreenView(
routeOnSuccess: RestoreFromEncryptedStringView.routeName, showBackButton: true,
routeOnSuccessArguments: encrypted, routeOnSuccess: RestoreFromEncryptedStringView.routeName,
biometricsCancelButtonString: "CANCEL", routeOnSuccessArguments: encrypted,
biometricsLocalizedReason: biometricsCancelButtonString: "CANCEL",
"Authenticate to restore ${AppConfig.appName} backup", biometricsLocalizedReason:
biometricsAuthenticationTitle: "Restore ${AppConfig.prefix} backup", "Authenticate to restore ${AppConfig.appName} backup",
biometricsAuthenticationTitle:
"Restore ${AppConfig.prefix} backup",
),
settings: const RouteSettings(name: "/swbrestorelockscreen"),
), ),
settings: const RouteSettings(name: "/swbrestorelockscreen"),
), ),
)); );
} }
} }
@ -659,7 +671,8 @@ class _MaterialAppWithThemeState extends ConsumerState<MaterialAppWithTheme>
foregroundColor: foregroundColor:
MaterialStateProperty.all(colorScheme.buttonTextSecondary), MaterialStateProperty.all(colorScheme.buttonTextSecondary),
backgroundColor: MaterialStateProperty.all<Color>( backgroundColor: MaterialStateProperty.all<Color>(
colorScheme.buttonBackSecondary), 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

View file

@ -10,7 +10,6 @@
import '../add_wallet_list_entity.dart'; import '../add_wallet_list_entity.dart';
import '../../isar/models/ethereum/eth_contract.dart'; import '../../isar/models/ethereum/eth_contract.dart';
import '../../../wallets/crypto_currency/coins/ethereum.dart';
import '../../../wallets/crypto_currency/crypto_currency.dart'; import '../../../wallets/crypto_currency/crypto_currency.dart';
class EthTokenEntity extends AddWalletListEntity { class EthTokenEntity extends AddWalletListEntity {

View file

@ -72,7 +72,8 @@ class Balance {
), ),
pendingSpendable: decoded["pendingSpendable"] is String pendingSpendable: decoded["pendingSpendable"] is String
? Amount.fromSerializedJsonString( ? Amount.fromSerializedJsonString(
decoded["pendingSpendable"] as String) decoded["pendingSpendable"] as String,
)
: Amount( : Amount(
rawValue: BigInt.from(decoded["pendingSpendable"] as int), rawValue: BigInt.from(decoded["pendingSpendable"] as int),
fractionDigits: deprecatedValue, fractionDigits: deprecatedValue,

View file

@ -23,11 +23,12 @@ class Fiat {
/// Fiat name /// Fiat name
final Decimal maxAmount; final Decimal maxAmount;
Fiat( Fiat({
{required this.ticker, required this.ticker,
required this.name, required this.name,
required this.minAmount, required this.minAmount,
required this.maxAmount}); required this.maxAmount,
});
factory Fiat.fromJson(Map<String, dynamic> json) { factory Fiat.fromJson(Map<String, dynamic> json) {
try { try {

View file

@ -9,6 +9,7 @@
*/ */
import 'package:decimal/decimal.dart'; import 'package:decimal/decimal.dart';
import '../response_objects/crypto.dart'; import '../response_objects/crypto.dart';
import '../response_objects/fiat.dart'; import '../response_objects/fiat.dart';
import '../response_objects/order.dart'; import '../response_objects/order.dart';
@ -20,7 +21,8 @@ class Simplex {
SimplexQuote quote = SimplexQuote( SimplexQuote quote = SimplexQuote(
crypto: Crypto.fromJson({'ticker': 'BTC', 'name': 'Bitcoin', 'image': ''}), crypto: Crypto.fromJson({'ticker': 'BTC', 'name': 'Bitcoin', 'image': ''}),
fiat: Fiat.fromJson( fiat: Fiat.fromJson(
{'ticker': 'USD', 'name': 'United States Dollar', 'image': ''}), {'ticker': 'USD', 'name': 'United States Dollar', 'image': ''},
),
youPayFiatPrice: Decimal.parse("100"), youPayFiatPrice: Decimal.parse("100"),
youReceiveCryptoAmount: Decimal.parse("1.0238917"), youReceiveCryptoAmount: Decimal.parse("1.0238917"),
id: "someID", id: "someID",
@ -28,20 +30,22 @@ class Simplex {
buyWithFiat: true, buyWithFiat: true,
); );
SimplexOrder order = SimplexOrder( SimplexOrder order = SimplexOrder(
quote: SimplexQuote( quote: SimplexQuote(
crypto: crypto:
Crypto.fromJson({'ticker': 'BTC', 'name': 'Bitcoin', 'image': ''}), Crypto.fromJson({'ticker': 'BTC', 'name': 'Bitcoin', 'image': ''}),
fiat: Fiat.fromJson( fiat: Fiat.fromJson(
{'ticker': 'USD', 'name': 'United States Dollar', 'image': ''}), {'ticker': 'USD', 'name': 'United States Dollar', 'image': ''},
youPayFiatPrice: Decimal.parse("100"),
youReceiveCryptoAmount: Decimal.parse("1.0238917"),
id: "someID",
receivingAddress: '',
buyWithFiat: true,
), ),
orderId: 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee', youPayFiatPrice: Decimal.parse("100"),
paymentId: 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee', youReceiveCryptoAmount: Decimal.parse("1.0238917"),
userId: 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee'); id: "someID",
receivingAddress: '',
buyWithFiat: true,
),
orderId: 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee',
paymentId: 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee',
userId: 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee',
);
void updateSupportedCryptos(List<Crypto> newCryptos) { void updateSupportedCryptos(List<Crypto> newCryptos) {
supportedCryptos = newCryptos; supportedCryptos = newCryptos;

View file

@ -44,13 +44,13 @@ class Contact {
List<ContactAddressEntry>? addresses, List<ContactAddressEntry>? addresses,
bool? isFavorite, bool? isFavorite,
}) { }) {
List<ContactAddressEntry> _addresses = []; final List<ContactAddressEntry> _addresses = [];
if (addresses == null) { if (addresses == null) {
for (var e in this.addresses) { for (final e in this.addresses) {
_addresses.add(e.copyWith()); _addresses.add(e.copyWith());
} }
} else { } else {
for (var e in addresses) { for (final e in addresses) {
_addresses.add(e.copyWith()); _addresses.add(e.copyWith());
} }
} }

View file

@ -11,6 +11,7 @@
import 'dart:convert'; import 'dart:convert';
import 'package:hive/hive.dart'; import 'package:hive/hive.dart';
import 'epicbox_server_model.dart'; import 'epicbox_server_model.dart';
part 'type_adaptors/epicbox_config_model.g.dart'; part 'type_adaptors/epicbox_config_model.g.dart';
@ -57,7 +58,7 @@ class EpicBoxConfigModel {
} }
Map<String, dynamic> toMap() { Map<String, dynamic> toMap() {
Map<String, dynamic> map = {}; final Map<String, dynamic> map = {};
map['epicbox_domain'] = host; map['epicbox_domain'] = host;
map['epicbox_port'] = port; map['epicbox_port'] = port;
map['epicbox_protocol_insecure'] = protocolInsecure; map['epicbox_protocol_insecure'] = protocolInsecure;
@ -84,7 +85,7 @@ class EpicBoxConfigModel {
} }
static EpicBoxConfigModel fromString(String epicBoxConfigString) { static EpicBoxConfigModel fromString(String epicBoxConfigString) {
dynamic _epicBox = json.decode(epicBoxConfigString); final dynamic _epicBox = json.decode(epicBoxConfigString);
// handle old epicbox config formats // handle old epicbox config formats
final oldDomain = _epicBox["domain"] ?? "empty"; final oldDomain = _epicBox["domain"] ?? "empty";
@ -117,8 +118,11 @@ class EpicBoxConfigModel {
); );
} }
static EpicBoxConfigModel fromServer(EpicBoxServerModel server, static EpicBoxConfigModel fromServer(
{bool? protocolInsecure, int? addressIndex}) { EpicBoxServerModel server, {
bool? protocolInsecure,
int? addressIndex,
}) {
return EpicBoxConfigModel( return EpicBoxConfigModel(
host: server.host, host: server.host,
port: server.port ?? 443, port: server.port ?? 443,

View file

@ -64,7 +64,7 @@ class EpicBoxServerModel {
} }
Map<String, dynamic> toMap() { Map<String, dynamic> toMap() {
Map<String, dynamic> map = {}; final Map<String, dynamic> map = {};
map['id'] = id; map['id'] = id;
map['host'] = host; map['host'] = host;
map['port'] = port; map['port'] = port;

View file

@ -9,6 +9,7 @@
*/ */
import 'package:decimal/decimal.dart'; import 'package:decimal/decimal.dart';
import '../../../utilities/logger.dart'; import '../../../utilities/logger.dart';
class EstimatedExchangeAmount { class EstimatedExchangeAmount {
@ -45,8 +46,10 @@ class EstimatedExchangeAmount {
factory EstimatedExchangeAmount.fromJson(Map<String, dynamic> json) { factory EstimatedExchangeAmount.fromJson(Map<String, dynamic> json) {
try { try {
return EstimatedExchangeAmount( return EstimatedExchangeAmount(
estimatedAmount: Decimal.parse(json["estimatedAmount"]?.toString() ?? estimatedAmount: Decimal.parse(
json["estimatedDeposit"].toString()), json["estimatedAmount"]?.toString() ??
json["estimatedDeposit"].toString(),
),
transactionSpeedForecast: transactionSpeedForecast:
json["transactionSpeedForecast"] as String? ?? "", json["transactionSpeedForecast"] as String? ?? "",
warningMessage: json["warningMessage"] as String?, warningMessage: json["warningMessage"] as String?,

View file

@ -10,13 +10,15 @@
import 'package:decimal/decimal.dart'; import 'package:decimal/decimal.dart';
import 'package:hive/hive.dart'; import 'package:hive/hive.dart';
import 'exchange_transaction_status.dart';
import 'package:uuid/uuid.dart'; import 'package:uuid/uuid.dart';
import 'exchange_transaction_status.dart';
part '../../type_adaptors/exchange_transaction.g.dart'; part '../../type_adaptors/exchange_transaction.g.dart';
@Deprecated( @Deprecated(
"Do not use. Migrated to Trade in db_version_migration to hive_data_version 2") "Do not use. Migrated to Trade in db_version_migration to hive_data_version 2",
)
// @HiveType(typeId: 13) // @HiveType(typeId: 13)
class ExchangeTransaction { class ExchangeTransaction {
/// You can use it to get transaction status at the Transaction status API endpoint /// You can use it to get transaction status at the Transaction status API endpoint
@ -114,7 +116,8 @@ class ExchangeTransaction {
statusString: json["statusString"] as String? ?? "", statusString: json["statusString"] as String? ?? "",
statusObject: json["statusObject"] is Map<String, dynamic> statusObject: json["statusObject"] is Map<String, dynamic>
? ExchangeTransactionStatus.fromJson( ? ExchangeTransactionStatus.fromJson(
json["statusObject"] as Map<String, dynamic>) json["statusObject"] as Map<String, dynamic>,
)
: null, : null,
); );
} catch (e) { } catch (e) {

View file

@ -9,6 +9,7 @@
*/ */
import 'package:hive/hive.dart'; import 'package:hive/hive.dart';
import '../../../utilities/logger.dart'; import '../../../utilities/logger.dart';
part '../../type_adaptors/exchange_transaction_status.g.dart'; part '../../type_adaptors/exchange_transaction_status.g.dart';
@ -38,7 +39,8 @@ ChangeNowTransactionStatus changeNowTransactionStatusFromStringIgnoreCase(
} }
} }
throw ArgumentError( throw ArgumentError(
"String value does not match any known ChangeNowTransactionStatus"); "String value does not match any known ChangeNowTransactionStatus",
);
} }
@HiveType(typeId: 16) @HiveType(typeId: 16)
@ -189,7 +191,8 @@ class ExchangeTransactionStatus {
try { try {
return ExchangeTransactionStatus( return ExchangeTransactionStatus(
status: changeNowTransactionStatusFromStringIgnoreCase( status: changeNowTransactionStatusFromStringIgnoreCase(
json["status"] as String), json["status"] as String,
),
payinAddress: json["payinAddress"] as String? ?? "", payinAddress: json["payinAddress"] as String? ?? "",
payoutAddress: json["payoutAddress"] as String? ?? "", payoutAddress: json["payoutAddress"] as String? ?? "",
fromCurrency: json["fromCurrency"] as String? ?? "", fromCurrency: json["fromCurrency"] as String? ?? "",

View file

@ -9,10 +9,15 @@
*/ */
import 'package:decimal/decimal.dart'; import 'package:decimal/decimal.dart';
import 'mb_object.dart'; import 'mb_object.dart';
class MBRate extends MBObject { class MBRate extends MBObject {
MBRate({required this.fromCurrency, required this.toCurrency, required this.rate,}); MBRate({
required this.fromCurrency,
required this.toCurrency,
required this.rate,
});
final String fromCurrency; final String fromCurrency;
final String toCurrency; final String toCurrency;

View file

@ -9,8 +9,9 @@
*/ */
import 'package:hive/hive.dart'; import 'package:hive/hive.dart';
import '../change_now/exchange_transaction.dart';
import '../../../services/exchange/change_now/change_now_exchange.dart'; import '../../../services/exchange/change_now/change_now_exchange.dart';
import '../change_now/exchange_transaction.dart';
part 'trade.g.dart'; part 'trade.g.dart';
@ -213,7 +214,9 @@ class Trade {
} }
factory Trade.fromExchangeTransaction( factory Trade.fromExchangeTransaction(
ExchangeTransaction exTx, bool reversed) { ExchangeTransaction exTx,
bool reversed,
) {
return Trade( return Trade(
uuid: exTx.uuid, uuid: exTx.uuid,
tradeId: exTx.id, tradeId: exTx.id,

View file

@ -59,8 +59,10 @@ class SPCurrency {
warningsTo: json["warnings_to"] as List<dynamic>, warningsTo: json["warnings_to"] as List<dynamic>,
); );
} catch (e, s) { } catch (e, s) {
Logging.instance.log("SPCurrency.fromJson failed to parse: $e\n$s", Logging.instance.log(
level: LogLevel.Error); "SPCurrency.fromJson failed to parse: $e\n$s",
level: LogLevel.Error,
);
rethrow; rethrow;
} }
} }

View file

@ -23,10 +23,12 @@ class Currency {
final String exchangeName; final String exchangeName;
/// Currency ticker /// Currency ticker
@Index(composite: [ @Index(
CompositeIndex("exchangeName"), composite: [
CompositeIndex("name"), CompositeIndex("exchangeName"),
]) CompositeIndex("name"),
],
)
final String ticker; final String ticker;
/// Currency name /// Currency name

View file

@ -29,10 +29,12 @@ class Pair {
@Index() @Index()
final String exchangeName; final String exchangeName;
@Index(composite: [ @Index(
CompositeIndex("exchangeName"), composite: [
CompositeIndex("to"), CompositeIndex("exchangeName"),
]) CompositeIndex("to"),
],
)
final String from; final String from;
final String to; final String to;

View file

@ -12,11 +12,12 @@ import 'dart:convert';
import 'dart:math'; import 'dart:math';
import 'package:isar/isar.dart'; import 'package:isar/isar.dart';
import 'package:tuple/tuple.dart';
import '../../../../utilities/amount/amount.dart';
import 'address.dart'; import 'address.dart';
import 'input.dart'; import 'input.dart';
import 'output.dart'; import 'output.dart';
import '../../../../utilities/amount/amount.dart';
import 'package:tuple/tuple.dart';
part 'transaction.g.dart'; part 'transaction.g.dart';
@ -65,24 +66,24 @@ class Transaction {
}) { }) {
return Tuple2( return Tuple2(
Transaction( Transaction(
walletId: walletId ?? this.walletId, walletId: walletId ?? this.walletId,
txid: txid ?? this.txid, txid: txid ?? this.txid,
timestamp: timestamp ?? this.timestamp, timestamp: timestamp ?? this.timestamp,
type: type ?? this.type, type: type ?? this.type,
subType: subType ?? this.subType, subType: subType ?? this.subType,
amount: amount ?? this.amount, amount: amount ?? this.amount,
amountString: amountString ?? this.amountString, amountString: amountString ?? this.amountString,
fee: fee ?? this.fee, fee: fee ?? this.fee,
height: height ?? this.height, height: height ?? this.height,
isCancelled: isCancelled ?? this.isCancelled, isCancelled: isCancelled ?? this.isCancelled,
isLelantus: isLelantus ?? this.isLelantus, isLelantus: isLelantus ?? this.isLelantus,
slateId: slateId ?? this.slateId, slateId: slateId ?? this.slateId,
otherData: otherData ?? this.otherData, otherData: otherData ?? this.otherData,
nonce: nonce ?? this.nonce, nonce: nonce ?? this.nonce,
inputs: inputs ?? this.inputs, inputs: inputs ?? this.inputs,
outputs: outputs ?? this.outputs, outputs: outputs ?? this.outputs,
numberOfMessages: numberOfMessages ?? this.numberOfMessages) numberOfMessages: numberOfMessages ?? this.numberOfMessages,
..id = id ?? this.id, )..id = id ?? this.id,
address ?? this.address.value, address ?? this.address.value,
); );
} }

View file

@ -38,10 +38,14 @@ class UTXO {
@Index() @Index()
late final String walletId; late final String walletId;
@Index(unique: true, replace: true, composite: [ @Index(
CompositeIndex("walletId"), unique: true,
CompositeIndex("vout"), replace: true,
]) composite: [
CompositeIndex("walletId"),
CompositeIndex("vout"),
],
)
late final String txid; late final String txid;
late final int vout; late final int vout;

View file

@ -54,7 +54,7 @@ class OutputV2 {
bool isFullAmountNotSats = false, bool isFullAmountNotSats = false,
}) { }) {
try { try {
List<String> addresses = []; final List<String> addresses = [];
if (json["scriptPubKey"]?["addresses"] is List) { if (json["scriptPubKey"]?["addresses"] is List) {
for (final e in json["scriptPubKey"]["addresses"] as List) { for (final e in json["scriptPubKey"]["addresses"] as List) {
@ -68,7 +68,7 @@ class OutputV2 {
scriptPubKeyHex: json["scriptPubKey"]["hex"] as String, scriptPubKeyHex: json["scriptPubKey"]["hex"] as String,
scriptPubKeyAsm: json["scriptPubKey"]["asm"] as String?, scriptPubKeyAsm: json["scriptPubKey"]["asm"] as String?,
valueStringSats: parseOutputAmountString( valueStringSats: parseOutputAmountString(
json["value"] != null ? json["value"].toString(): "0", json["value"] != null ? json["value"].toString() : "0",
decimalPlaces: decimalPlaces, decimalPlaces: decimalPlaces,
isFullAmountNotSats: isFullAmountNotSats, isFullAmountNotSats: isFullAmountNotSats,
), ),

View file

@ -124,12 +124,14 @@ const _LoglogLevelEnumValueMap = {
r'Warning': r'Warning', r'Warning': r'Warning',
r'Error': r'Error', r'Error': r'Error',
r'Fatal': r'Fatal', r'Fatal': r'Fatal',
r'Debug': r'Debug',
}; };
const _LoglogLevelValueEnumMap = { const _LoglogLevelValueEnumMap = {
r'Info': LogLevel.Info, r'Info': LogLevel.Info,
r'Warning': LogLevel.Warning, r'Warning': LogLevel.Warning,
r'Error': LogLevel.Error, r'Error': LogLevel.Error,
r'Fatal': LogLevel.Fatal, r'Fatal': LogLevel.Fatal,
r'Debug': LogLevel.Debug,
}; };
Id _logGetId(Log object) { Id _logGetId(Log object) {

View file

@ -1,4 +1,5 @@
import 'package:isar/isar.dart'; import 'package:isar/isar.dart';
import '../../db/isar/main_db.dart'; import '../../db/isar/main_db.dart';
import '../../dto/ordinals/inscription_data.dart'; import '../../dto/ordinals/inscription_data.dart';
import 'models/isar_models.dart'; import 'models/isar_models.dart';
@ -11,10 +12,14 @@ class Ordinal {
final String walletId; final String walletId;
@Index(unique: true, replace: true, composite: [ @Index(
CompositeIndex("utxoTXID"), unique: true,
CompositeIndex("utxoVOUT"), replace: true,
]) composite: [
CompositeIndex("utxoTXID"),
CompositeIndex("utxoVOUT"),
],
)
final String inscriptionId; final String inscriptionId;
final int inscriptionNumber; final int inscriptionNumber;

View file

@ -40,7 +40,7 @@ class LelantusCoin {
@override @override
String toString() { String toString() {
String coin = final String coin =
"{index: $index, value: $value, publicCoin: $publicCoin, txId: $txId, anonymitySetId: $anonymitySetId, isUsed: $isUsed}"; "{index: $index, value: $value, publicCoin: $publicCoin, txId: $txId, anonymitySetId: $anonymitySetId, isUsed: $isUsed}";
return coin; return coin;
} }

View file

@ -86,7 +86,7 @@ class NodeModel {
} }
Map<String, dynamic> toMap() { Map<String, dynamic> toMap() {
Map<String, dynamic> map = {}; final Map<String, dynamic> map = {};
map['host'] = host; map['host'] = host;
map['port'] = port; map['port'] = port;
map['name'] = name; map['name'] = name;

View file

@ -34,29 +34,32 @@ class TransactionData {
TransactionData({this.txChunks = const []}); TransactionData({this.txChunks = const []});
factory TransactionData.fromJson(Map<String, dynamic> json) { factory TransactionData.fromJson(Map<String, dynamic> json) {
var dateTimeChunks = json['dateTimeChunks'] as List; final dateTimeChunks = json['dateTimeChunks'] as List;
List<TransactionChunk> chunksList = dateTimeChunks final List<TransactionChunk> chunksList = dateTimeChunks
.map((txChunk) => .map(
TransactionChunk.fromJson(txChunk as Map<String, dynamic>)) (txChunk) =>
TransactionChunk.fromJson(txChunk as Map<String, dynamic>),
)
.toList(); .toList();
return TransactionData(txChunks: chunksList); return TransactionData(txChunks: chunksList);
} }
factory TransactionData.fromMap(Map<String, Transaction> transactions) { factory TransactionData.fromMap(Map<String, Transaction> transactions) {
Map<String, List<Transaction>> chunks = {}; final Map<String, List<Transaction>> chunks = {};
transactions.forEach((key, value) { transactions.forEach((key, value) {
String date = extractDateFromTimestamp(value.timestamp); final String date = extractDateFromTimestamp(value.timestamp);
if (!chunks.containsKey(date)) { if (!chunks.containsKey(date)) {
chunks[date] = []; chunks[date] = [];
} }
chunks[date]!.add(value); chunks[date]!.add(value);
}); });
List<TransactionChunk> chunksList = []; final List<TransactionChunk> chunksList = [];
chunks.forEach((key, value) { chunks.forEach((key, value) {
value.sort((a, b) => b.timestamp.compareTo(a.timestamp)); value.sort((a, b) => b.timestamp.compareTo(a.timestamp));
chunksList.add( chunksList.add(
TransactionChunk(timestamp: value[0].timestamp, transactions: value)); TransactionChunk(timestamp: value[0].timestamp, transactions: value),
);
}); });
chunksList.sort((a, b) => b.timestamp.compareTo(a.timestamp)); chunksList.sort((a, b) => b.timestamp.compareTo(a.timestamp));
return TransactionData(txChunks: chunksList); return TransactionData(txChunks: chunksList);
@ -64,9 +67,9 @@ class TransactionData {
Transaction? findTransaction(String txid) { Transaction? findTransaction(String txid) {
for (var i = 0; i < txChunks.length; i++) { for (var i = 0; i < txChunks.length; i++) {
var txChunk = txChunks[i].transactions; final txChunk = txChunks[i].transactions;
for (var j = 0; j < txChunk.length; j++) { for (var j = 0; j < txChunk.length; j++) {
var tx = txChunk[j]; final tx = txChunk[j];
if (tx.txid == txid) { if (tx.txid == txid) {
return tx; return tx;
} }
@ -76,11 +79,11 @@ class TransactionData {
} }
Map<String, Transaction> getAllTransactions() { Map<String, Transaction> getAllTransactions() {
Map<String, Transaction> transactions = {}; final Map<String, Transaction> transactions = {};
for (var i = 0; i < txChunks.length; i++) { for (var i = 0; i < txChunks.length; i++) {
var txChunk = txChunks[i].transactions; final txChunk = txChunks[i].transactions;
for (var j = 0; j < txChunk.length; j++) { for (var j = 0; j < txChunk.length; j++) {
var tx = txChunk[j]; final tx = txChunk[j];
transactions[tx.txid] = tx; transactions[tx.txid] = tx;
} }
} }
@ -98,14 +101,15 @@ class TransactionChunk {
TransactionChunk({required this.timestamp, required this.transactions}); TransactionChunk({required this.timestamp, required this.transactions});
factory TransactionChunk.fromJson(Map<String, dynamic> json) { factory TransactionChunk.fromJson(Map<String, dynamic> json) {
var txArray = json['transactions'] as List; final txArray = json['transactions'] as List;
List<Transaction> txList = txArray final List<Transaction> txList = txArray
.map((tx) => Transaction.fromJson(tx as Map<String, dynamic>)) .map((tx) => Transaction.fromJson(tx as Map<String, dynamic>))
.toList(); .toList();
return TransactionChunk( return TransactionChunk(
timestamp: int.parse(json['timestamp'].toString()), timestamp: int.parse(json['timestamp'].toString()),
transactions: txList); transactions: txList,
);
} }
@override @override
@ -191,15 +195,16 @@ class Transaction {
}); });
factory Transaction.fromJson(Map<String, dynamic> json) { factory Transaction.fromJson(Map<String, dynamic> json) {
var inputArray = json['inputs'] as List; final inputArray = json['inputs'] as List;
var outputArray = json['outputs'] as List; final outputArray = json['outputs'] as List;
List<Input> inputList = inputArray final List<Input> inputList = inputArray
.map((input) => Input.fromJson(Map<String, dynamic>.from(input as Map))) .map((input) => Input.fromJson(Map<String, dynamic>.from(input as Map)))
.toList(); .toList();
List<Output> outputList = outputArray final List<Output> outputList = outputArray
.map((output) => .map(
Output.fromJson(Map<String, dynamic>.from(output as Map))) (output) => Output.fromJson(Map<String, dynamic>.from(output as Map)),
)
.toList(); .toList();
return Transaction( return Transaction(
@ -304,7 +309,7 @@ class Transaction {
@override @override
String toString() { String toString() {
String transaction = final String transaction =
"{txid: $txid, type: $txType, subType: $subType, value: $amount, fee: $fees, height: $height, confirm: $confirmedStatus, confirmations: $confirmations, address: $address, timestamp: $timestamp, worthNow: $worthNow, inputs: $inputs, slateid: $slateId, numberOfMessages: $numberOfMessages }"; "{txid: $txid, type: $txType, subType: $subType, value: $amount, fee: $fees, height: $height, confirm: $confirmedStatus, confirmations: $confirmations, address: $address, timestamp: $timestamp, worthNow: $worthNow, inputs: $inputs, slateid: $slateId, numberOfMessages: $numberOfMessages }";
return transaction; return transaction;
} }
@ -344,7 +349,7 @@ class Input {
}); });
factory Input.fromJson(Map<String, dynamic> json) { factory Input.fromJson(Map<String, dynamic> json) {
bool iscoinBase = json['coinbase'] != null; final bool iscoinBase = json['coinbase'] != null;
return Input( return Input(
txid: json['txid'] as String? ?? "", txid: json['txid'] as String? ?? "",
vout: json['vout'] as int? ?? -1, vout: json['vout'] as int? ?? -1,
@ -361,7 +366,7 @@ class Input {
@override @override
String toString() { String toString() {
String transaction = "{txid: $txid}"; final String transaction = "{txid: $txid}";
return transaction; return transaction;
} }
} }
@ -383,12 +388,13 @@ class Output {
// @HiveField(4) // @HiveField(4)
final int value; final int value;
Output( Output({
{this.scriptpubkey, this.scriptpubkey,
this.scriptpubkeyAsm, this.scriptpubkeyAsm,
this.scriptpubkeyType, this.scriptpubkeyType,
required this.scriptpubkeyAddress, required this.scriptpubkeyAddress,
required this.value}); required this.value,
});
factory Output.fromJson(Map<String, dynamic> json) { factory Output.fromJson(Map<String, dynamic> json) {
// TODO determine if any of this code is needed. // TODO determine if any of this code is needed.
@ -405,12 +411,13 @@ class Output {
); );
} catch (s, e) { } catch (s, e) {
return Output( return Output(
// Return output object with null values; allows wallet history to be built // Return output object with null values; allows wallet history to be built
scriptpubkey: "", scriptpubkey: "",
scriptpubkeyAsm: "", scriptpubkeyAsm: "",
scriptpubkeyType: "", scriptpubkeyType: "",
scriptpubkeyAddress: "", scriptpubkeyAddress: "",
value: _parse(0.toString())); value: _parse(0.toString()),
);
} }
} }
} }

View file

@ -35,8 +35,8 @@ class UtxoData {
}); });
factory UtxoData.fromJson(Map<String, dynamic> json) { factory UtxoData.fromJson(Map<String, dynamic> json) {
var outputList = json['outputArray'] as List; final outputList = json['outputArray'] as List;
List<UtxoObject> utxoList = outputList final List<UtxoObject> utxoList = outputList
.map((output) => UtxoObject.fromJson(output as Map<String, dynamic>)) .map((output) => UtxoObject.fromJson(output as Map<String, dynamic>))
.toList(); .toList();
final String totalUserCurr = json['total_user_currency'] as String? ?? ""; final String totalUserCurr = json['total_user_currency'] as String? ?? "";
@ -104,7 +104,7 @@ class UtxoObject {
@override @override
String toString() { String toString() {
String utxo = final String utxo =
"{txid: $txid, vout: $vout, value: $value, fiat: $fiatWorth, blocked: $blocked, status: $status, is_coinbase: $isCoinbase}"; "{txid: $txid, vout: $vout, value: $value, fiat: $fiatWorth, blocked: $blocked, status: $status, is_coinbase: $isCoinbase}";
return utxo; return utxo;

View file

@ -44,12 +44,16 @@ class PaynymAccount {
.map((e) => PaynymCode.fromMap(Map<String, dynamic>.from(e as Map))) .map((e) => PaynymCode.fromMap(Map<String, dynamic>.from(e as Map)))
.toList(), .toList(),
followers = (map["followers"] as List<dynamic>) followers = (map["followers"] as List<dynamic>)
.map((e) => .map(
PaynymAccountLite.fromMap(Map<String, dynamic>.from(e as Map))) (e) => PaynymAccountLite.fromMap(
Map<String, dynamic>.from(e as Map)),
)
.toList(), .toList(),
following = (map["following"] as List<dynamic>) following = (map["following"] as List<dynamic>)
.map((e) => .map(
PaynymAccountLite.fromMap(Map<String, dynamic>.from(e as Map))) (e) => PaynymAccountLite.fromMap(
Map<String, dynamic>.from(e as Map)),
)
.toList(); .toList();
PaynymAccount copyWith({ PaynymAccount copyWith({

View file

@ -21,13 +21,13 @@ class PaynymFollow {
token = map["token"] as String; token = map["token"] as String;
Map<String, dynamic> toMap() => { Map<String, dynamic> toMap() => {
"follower": follower, "follower": follower,
"following": following, "following": following,
"token": token, "token": token,
}; };
@override @override
String toString() { String toString() {
return toMap().toString(); return toMap().toString();
} }
} }

View file

@ -10,9 +10,10 @@
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'wallet_restore_state.dart';
import '../utilities/enums/stack_restoring_status.dart'; import '../utilities/enums/stack_restoring_status.dart';
import '../wallets/wallet/wallet.dart'; import '../wallets/wallet/wallet.dart';
import 'wallet_restore_state.dart';
class StackRestoringUIState extends ChangeNotifier { class StackRestoringUIState extends ChangeNotifier {
bool _walletsWasSet = false; bool _walletsWasSet = false;
@ -94,7 +95,7 @@ class StackRestoringUIState extends ChangeNotifier {
} }
List<Wallet> get wallets { List<Wallet> get wallets {
List<Wallet> _wallets = []; final List<Wallet> _wallets = [];
for (final item in _walletStates.values) { for (final item in _walletStates.values) {
if (item.wallet != null) { if (item.wallet != null) {
_wallets.add(item.wallet!); _wallets.add(item.wallet!);
@ -125,7 +126,8 @@ class StackRestoringUIState extends ChangeNotifier {
} }
ChangeNotifierProvider<WalletRestoreState> getWalletRestoreStateProvider( ChangeNotifierProvider<WalletRestoreState> getWalletRestoreStateProvider(
String walletId) { String walletId,
) {
return _walletStateProviders[walletId]!; return _walletStateProviders[walletId]!;
} }

View file

@ -13,6 +13,7 @@ import 'dart:io';
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:flutter_svg/svg.dart'; import 'package:flutter_svg/svg.dart';
import '../app_config.dart'; import '../app_config.dart';
import '../models/isar/stack_theme.dart'; import '../models/isar/stack_theme.dart';
import '../models/notification_model.dart'; import '../models/notification_model.dart';
@ -28,9 +29,9 @@ import '../widgets/rounded_white_container.dart';
class NotificationCard extends ConsumerWidget { class NotificationCard extends ConsumerWidget {
const NotificationCard({ const NotificationCard({
Key? key, super.key,
required this.notification, required this.notification,
}) : super(key: key); });
final NotificationModel notification; final NotificationModel notification;
@ -71,10 +72,11 @@ class NotificationCard extends ConsumerWidget {
? SvgPicture.file( ? SvgPicture.file(
File( File(
coinIconPath( coinIconPath(
ref.watch( ref.watch(
themeAssetsProvider, themeAssetsProvider,
), ),
ref), ref,
),
), ),
width: isDesktop ? desktopIconSize : mobileIconSize, width: isDesktop ? desktopIconSize : mobileIconSize,
height: isDesktop ? desktopIconSize : mobileIconSize, height: isDesktop ? desktopIconSize : mobileIconSize,
@ -89,10 +91,11 @@ class NotificationCard extends ConsumerWidget {
child: SvgPicture.file( child: SvgPicture.file(
File( File(
coinIconPath( coinIconPath(
ref.watch( ref.watch(
themeAssetsProvider, themeAssetsProvider,
), ),
ref), ref,
),
), ),
color: Theme.of(context) color: Theme.of(context)
.extension<StackColors>()! .extension<StackColors>()!
@ -123,7 +126,7 @@ class NotificationCard extends ConsumerWidget {
.extension<StackColors>()! .extension<StackColors>()!
.accentColorGreen, .accentColorGreen,
), ),
) ),
], ],
), ),
child: Text( child: Text(

View file

@ -11,7 +11,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class TermsOfServiceView extends StatelessWidget { class TermsOfServiceView extends StatelessWidget {
const TermsOfServiceView({Key? key}) : super(key: key); const TermsOfServiceView({super.key});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {

View file

@ -13,6 +13,7 @@ import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../../../models/isar/models/ethereum/eth_contract.dart'; import '../../../models/isar/models/ethereum/eth_contract.dart';
import '../../../services/ethereum/ethereum_api.dart'; import '../../../services/ethereum/ethereum_api.dart';
import '../../../themes/stack_colors.dart'; import '../../../themes/stack_colors.dart';
@ -29,8 +30,8 @@ import '../../../widgets/stack_dialog.dart';
class AddCustomTokenView extends ConsumerStatefulWidget { class AddCustomTokenView extends ConsumerStatefulWidget {
const AddCustomTokenView({ const AddCustomTokenView({
Key? key, super.key,
}) : super(key: key); });
static const routeName = "/addCustomToken"; static const routeName = "/addCustomToken";
@ -138,7 +139,8 @@ class _AddCustomTokenViewState extends ConsumerState<AddCustomTokenView> {
onPressed: () async { onPressed: () async {
final response = await showLoading( final response = await showLoading(
whileFuture: EthereumAPI.getTokenContractInfoByAddress( whileFuture: EthereumAPI.getTokenContractInfoByAddress(
contractController.text), contractController.text,
),
context: context, context: context,
message: "Looking up contract", message: "Looking up contract",
); );
@ -212,10 +214,12 @@ class _AddCustomTokenViewState extends ConsumerState<AddCustomTokenView> {
controller: decimalsController, controller: decimalsController,
style: STextStyles.field(context), style: STextStyles.field(context),
inputFormatters: [ inputFormatters: [
TextInputFormatter.withFunction((oldValue, newValue) => TextInputFormatter.withFunction(
RegExp(r'^([0-9]*)$').hasMatch(newValue.text) (oldValue, newValue) =>
? newValue RegExp(r'^([0-9]*)$').hasMatch(newValue.text)
: oldValue), ? newValue
: oldValue,
),
], ],
keyboardType: const TextInputType.numberWithOptions( keyboardType: const TextInputType.numberWithOptions(
signed: false, signed: false,
@ -253,10 +257,12 @@ class _AddCustomTokenViewState extends ConsumerState<AddCustomTokenView> {
controller: decimalsController, controller: decimalsController,
style: STextStyles.field(context), style: STextStyles.field(context),
inputFormatters: [ inputFormatters: [
TextInputFormatter.withFunction((oldValue, newValue) => TextInputFormatter.withFunction(
RegExp(r'^([0-9]*)$').hasMatch(newValue.text) (oldValue, newValue) =>
? newValue RegExp(r'^([0-9]*)$').hasMatch(newValue.text)
: oldValue), ? newValue
: oldValue,
),
], ],
keyboardType: const TextInputType.numberWithOptions( keyboardType: const TextInputType.numberWithOptions(
signed: false, signed: false,

View file

@ -14,14 +14,10 @@ import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/svg.dart'; import 'package:flutter_svg/svg.dart';
import 'package:isar/isar.dart'; import 'package:isar/isar.dart';
import '../../../db/isar/main_db.dart'; import '../../../db/isar/main_db.dart';
import '../../../models/isar/models/ethereum/eth_contract.dart'; import '../../../models/isar/models/ethereum/eth_contract.dart';
import '../../../notifications/show_flush_bar.dart'; import '../../../notifications/show_flush_bar.dart';
import 'add_custom_token_view.dart';
import 'sub_widgets/add_token_list.dart';
import 'sub_widgets/add_token_list_element.dart';
import 'sub_widgets/add_token_text.dart';
import '../../home_view/home_view.dart';
import '../../../pages_desktop_specific/desktop_home_view.dart'; import '../../../pages_desktop_specific/desktop_home_view.dart';
import '../../../providers/global/price_provider.dart'; import '../../../providers/global/price_provider.dart';
import '../../../providers/global/wallets_provider.dart'; import '../../../providers/global/wallets_provider.dart';
@ -46,14 +42,19 @@ import '../../../widgets/icon_widgets/x_icon.dart';
import '../../../widgets/rounded_white_container.dart'; import '../../../widgets/rounded_white_container.dart';
import '../../../widgets/stack_text_field.dart'; import '../../../widgets/stack_text_field.dart';
import '../../../widgets/textfield_icon_button.dart'; import '../../../widgets/textfield_icon_button.dart';
import '../../home_view/home_view.dart';
import 'add_custom_token_view.dart';
import 'sub_widgets/add_token_list.dart';
import 'sub_widgets/add_token_list_element.dart';
import 'sub_widgets/add_token_text.dart';
class EditWalletTokensView extends ConsumerStatefulWidget { class EditWalletTokensView extends ConsumerStatefulWidget {
const EditWalletTokensView({ const EditWalletTokensView({
Key? key, super.key,
required this.walletId, required this.walletId,
this.contractsToMarkSelected, this.contractsToMarkSelected,
this.isDesktopPopup = false, this.isDesktopPopup = false,
}) : super(key: key); });
final String walletId; final String walletId;
final List<String>? contractsToMarkSelected; final List<String>? contractsToMarkSelected;
@ -178,7 +179,8 @@ class _EditWalletTokensViewState extends ConsumerState<EditWalletTokensView> {
if (contracts.isEmpty) { if (contracts.isEmpty) {
contracts.addAll(DefaultTokens.list); contracts.addAll(DefaultTokens.list);
MainDB.instance.putEthContracts(contracts).then( MainDB.instance.putEthContracts(contracts).then(
(_) => ref.read(priceAnd24hChangeNotifierProvider).updatePrice()); (_) => ref.read(priceAnd24hChangeNotifierProvider).updatePrice(),
);
} }
tokenEntities.addAll(contracts.map((e) => AddTokenListElementData(e))); tokenEntities.addAll(contracts.map((e) => AddTokenListElementData(e)));
@ -241,7 +243,8 @@ class _EditWalletTokensViewState extends ConsumerState<EditWalletTokensView> {
"Add custom token", "Add custom token",
style: style:
STextStyles.desktopButtonSmallSecondaryEnabled( STextStyles.desktopButtonSmallSecondaryEnabled(
context), context,
),
), ),
), ),
), ),

View file

@ -18,9 +18,9 @@ import '../../../../utilities/util.dart';
class AddCustomTokenSelector extends StatelessWidget { class AddCustomTokenSelector extends StatelessWidget {
const AddCustomTokenSelector({ const AddCustomTokenSelector({
Key? key, super.key,
required this.addFunction, required this.addFunction,
}) : super(key: key); });
final VoidCallback addFunction; final VoidCallback addFunction;

View file

@ -15,11 +15,11 @@ import '../../../../widgets/conditional_parent.dart';
class AddTokenList extends StatelessWidget { class AddTokenList extends StatelessWidget {
const AddTokenList({ const AddTokenList({
Key? key, super.key,
required this.walletId, required this.walletId,
required this.items, required this.items,
required this.addFunction, required this.addFunction,
}) : super(key: key); });
final String walletId; final String walletId;
final List<AddTokenListElementData> items; final List<AddTokenListElementData> items;

View file

@ -13,10 +13,10 @@ import '../../../../utilities/text_styles.dart';
class AddTokenText extends StatelessWidget { class AddTokenText extends StatelessWidget {
const AddTokenText({ const AddTokenText({
Key? key, super.key,
required this.isDesktop, required this.isDesktop,
this.walletName, this.walletName,
}) : super(key: key); });
final String? walletName; final String? walletName;
final bool isDesktop; final bool isDesktop;

View file

@ -9,7 +9,6 @@
*/ */
import 'dart:async'; import 'dart:async';
import 'dart:io';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -132,11 +131,6 @@ class _AddWalletViewState extends ConsumerState<AddWalletView> {
_searchFieldController = TextEditingController(); _searchFieldController = TextEditingController();
_searchFocusNode = FocusNode(); _searchFocusNode = FocusNode();
// _coinsTestnet.remove(Coin.firoTestNet); // _coinsTestnet.remove(Coin.firoTestNet);
if (Platform.isWindows) {
_coins.removeWhere((e) => e is Monero || e is Wownero);
} else if (Platform.isLinux) {
_coins.removeWhere((e) => e is Wownero);
}
if (Util.isDesktop && !kDebugMode) { if (Util.isDesktop && !kDebugMode) {
_coins.removeWhere((e) => e is BitcoinFrost); _coins.removeWhere((e) => e is BitcoinFrost);
@ -154,8 +148,10 @@ class _AddWalletViewState extends ConsumerState<AddWalletView> {
if (contracts.isEmpty) { if (contracts.isEmpty) {
contracts.addAll(DefaultTokens.list); contracts.addAll(DefaultTokens.list);
MainDB.instance.putEthContracts(contracts).then((value) => MainDB.instance.putEthContracts(contracts).then(
ref.read(priceAnd24hChangeNotifierProvider).updatePrice()); (value) =>
ref.read(priceAnd24hChangeNotifierProvider).updatePrice(),
);
} }
tokenEntities.addAll(contracts.map((e) => EthTokenEntity(e))); tokenEntities.addAll(contracts.map((e) => EthTokenEntity(e)));
@ -354,63 +350,63 @@ class _AddWalletViewState extends ConsumerState<AddWalletView> {
height: 16, height: 16,
), ),
ClipRRect( ClipRRect(
borderRadius: BorderRadius.circular( borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius, Constants.size.circularBorderRadius,
), ),
child: Semantics( child: Semantics(
label: label:
"Search Text Field. Inputs Text To Search In Wallets.", "Search Text Field. Inputs Text To Search In Wallets.",
excludeSemantics: true, excludeSemantics: true,
child: TextField( child: TextField(
autofocus: isDesktop, autofocus: isDesktop,
autocorrect: !isDesktop, autocorrect: !isDesktop,
enableSuggestions: !isDesktop, enableSuggestions: !isDesktop,
controller: _searchFieldController, controller: _searchFieldController,
focusNode: _searchFocusNode, focusNode: _searchFocusNode,
onChanged: (value) => onChanged: (value) =>
setState(() => _searchTerm = value), setState(() => _searchTerm = value),
style: STextStyles.field(context), style: STextStyles.field(context),
decoration: standardInputDecoration( decoration: standardInputDecoration(
"Search", "Search",
_searchFocusNode, _searchFocusNode,
context, context,
desktopMed: isDesktop, desktopMed: isDesktop,
).copyWith( ).copyWith(
prefixIcon: Padding( prefixIcon: Padding(
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
horizontal: 10, horizontal: 10,
vertical: 16, vertical: 16,
), ),
child: SvgPicture.asset( child: SvgPicture.asset(
Assets.svg.search, Assets.svg.search,
width: 16, width: 16,
height: 16, height: 16,
),
), ),
suffixIcon: _searchFieldController.text.isNotEmpty
? Padding(
padding: const EdgeInsets.only(right: 0),
child: UnconstrainedBox(
child: Row(
children: [
TextFieldIconButton(
child: const XIcon(),
onTap: () async {
setState(() {
_searchFieldController.text =
"";
_searchTerm = "";
});
},
),
],
),
),
)
: null,
), ),
suffixIcon: _searchFieldController.text.isNotEmpty
? Padding(
padding: const EdgeInsets.only(right: 0),
child: UnconstrainedBox(
child: Row(
children: [
TextFieldIconButton(
child: const XIcon(),
onTap: () async {
setState(() {
_searchFieldController.text = "";
_searchTerm = "";
});
},
),
],
),
),
)
: null,
), ),
)), ),
),
),
const SizedBox( const SizedBox(
height: 10, height: 10,
), ),

View file

@ -14,10 +14,10 @@ import 'coin_select_item.dart';
class AddWalletEntityList extends StatelessWidget { class AddWalletEntityList extends StatelessWidget {
const AddWalletEntityList({ const AddWalletEntityList({
Key? key, super.key,
required this.entities, required this.entities,
this.trailing, this.trailing,
}) : super(key: key); });
final List<AddWalletListEntity> entities; final List<AddWalletListEntity> entities;
final Widget? trailing; final Widget? trailing;

View file

@ -10,27 +10,27 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart'; import 'package:flutter_svg/svg.dart';
import '../../../../models/add_wallet_list_entity/add_wallet_list_entity.dart'; import '../../../../models/add_wallet_list_entity/add_wallet_list_entity.dart';
import 'add_wallet_entity_list.dart';
import '../../../../themes/stack_colors.dart'; import '../../../../themes/stack_colors.dart';
import '../../../../utilities/assets.dart'; import '../../../../utilities/assets.dart';
import '../../../../utilities/text_styles.dart'; import '../../../../utilities/text_styles.dart';
import '../../../../utilities/util.dart'; import '../../../../utilities/util.dart';
import '../../../../widgets/animated_widgets/rotate_icon.dart'; import '../../../../widgets/animated_widgets/rotate_icon.dart';
import '../../../../widgets/expandable.dart'; import '../../../../widgets/expandable.dart';
import 'add_wallet_entity_list.dart';
class ExpandingSubListItem extends StatefulWidget { class ExpandingSubListItem extends StatefulWidget {
const ExpandingSubListItem({ const ExpandingSubListItem({
Key? key, super.key,
required this.title, required this.title,
required this.entities, required this.entities,
this.trailing, this.trailing,
required this.initialState, required this.initialState,
double? animationDurationMultiplier, double? animationDurationMultiplier,
this.curve = Curves.easeInOutCubicEmphasized, this.curve = Curves.easeInOutCubicEmphasized,
}) : animationDurationMultiplier = }) : animationDurationMultiplier =
animationDurationMultiplier ?? entities.length * 0.11, animationDurationMultiplier ?? entities.length * 0.11;
super(key: key);
final String title; final String title;
final List<AddWalletListEntity> entities; final List<AddWalletListEntity> entities;

View file

@ -19,9 +19,9 @@ import '../../../../utilities/text_styles.dart';
class AddWalletNextButton extends ConsumerWidget { class AddWalletNextButton extends ConsumerWidget {
const AddWalletNextButton({ const AddWalletNextButton({
Key? key, super.key,
required this.isDesktop, required this.isDesktop,
}) : super(key: key); });
final bool isDesktop; final bool isDesktop;

View file

@ -13,9 +13,9 @@ import '../../../../utilities/text_styles.dart';
class CreateRestoreWalletSubTitle extends StatelessWidget { class CreateRestoreWalletSubTitle extends StatelessWidget {
const CreateRestoreWalletSubTitle({ const CreateRestoreWalletSubTitle({
Key? key, super.key,
required this.isDesktop, required this.isDesktop,
}) : super(key: key); });
final bool isDesktop; final bool isDesktop;

View file

@ -8,16 +8,14 @@
* *
*/ */
import 'dart:io';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import '../../name_your_wallet_view/name_your_wallet_view.dart'; import 'package:tuple/tuple.dart';
import '../../../../themes/stack_colors.dart'; import '../../../../themes/stack_colors.dart';
import '../../../../utilities/enums/add_wallet_type_enum.dart'; import '../../../../utilities/enums/add_wallet_type_enum.dart';
import '../../../../utilities/text_styles.dart'; import '../../../../utilities/text_styles.dart';
import '../../../../wallets/crypto_currency/coins/wownero.dart';
import '../../../../wallets/crypto_currency/crypto_currency.dart'; import '../../../../wallets/crypto_currency/crypto_currency.dart';
import 'package:tuple/tuple.dart'; import '../../name_your_wallet_view/name_your_wallet_view.dart';
class CreateWalletButtonGroup extends StatelessWidget { class CreateWalletButtonGroup extends StatelessWidget {
const CreateWalletButtonGroup({ const CreateWalletButtonGroup({
@ -35,37 +33,35 @@ class CreateWalletButtonGroup extends StatelessWidget {
crossAxisAlignment: crossAxisAlignment:
isDesktop ? CrossAxisAlignment.center : CrossAxisAlignment.stretch, isDesktop ? CrossAxisAlignment.center : CrossAxisAlignment.stretch,
children: [ children: [
if (Platform.isAndroid || coin is! Wownero) ConstrainedBox(
ConstrainedBox( constraints: BoxConstraints(
constraints: BoxConstraints( minHeight: isDesktop ? 70 : 0,
minHeight: isDesktop ? 70 : 0, minWidth: isDesktop ? 480 : 0,
minWidth: isDesktop ? 480 : 0, ),
), child: TextButton(
child: TextButton( style: Theme.of(context)
style: Theme.of(context) .extension<StackColors>()!
.extension<StackColors>()! .getPrimaryEnabledButtonStyle(context),
.getPrimaryEnabledButtonStyle(context), onPressed: () {
onPressed: () { Navigator.of(context).pushNamed(
Navigator.of(context).pushNamed( NameYourWalletView.routeName,
NameYourWalletView.routeName, arguments: Tuple2(
arguments: Tuple2( AddWalletType.New,
AddWalletType.New, coin,
coin, ),
), );
); },
}, child: Text(
child: Text( "Create new wallet",
"Create new wallet", style: isDesktop
style: isDesktop ? STextStyles.desktopButtonEnabled(context)
? STextStyles.desktopButtonEnabled(context) : STextStyles.button(context),
: STextStyles.button(context),
),
), ),
), ),
if (Platform.isAndroid || coin is! Wownero) ),
SizedBox( SizedBox(
height: isDesktop ? 16 : 12, height: isDesktop ? 16 : 12,
), ),
ConstrainedBox( ConstrainedBox(
constraints: BoxConstraints( constraints: BoxConstraints(
minHeight: isDesktop ? 70 : 0, minHeight: isDesktop ? 70 : 0,
@ -91,7 +87,8 @@ class CreateWalletButtonGroup extends StatelessWidget {
: STextStyles.button(context).copyWith( : STextStyles.button(context).copyWith(
color: Theme.of(context) color: Theme.of(context)
.extension<StackColors>()! .extension<StackColors>()!
.accentColorDark), .accentColorDark,
),
), ),
), ),
), ),

View file

@ -167,7 +167,7 @@ class _SelectNewFrostImportTypeViewState
FrostStepScaffold.routeName, FrostStepScaffold.routeName,
); );
}, },
) ),
], ],
), ),
), ),

View file

@ -176,7 +176,7 @@ class _FrostCreateStep1bState extends ConsumerState<FrostCreateStep1b> {
.routeName, .routeName,
); );
}, },
) ),
], ],
), ),
); );

View file

@ -70,7 +70,7 @@ class _FrostCreateStep4State extends ConsumerState<FrostCreateStep4> {
.routeName, .routeName,
); );
}, },
) ),
], ],
), ),
); );

View file

@ -222,7 +222,7 @@ class _FrostReshareStep1cState extends ConsumerState<FrostReshareStep1c> {
_buttonLock = false; _buttonLock = false;
} }
}, },
) ),
], ],
), ),
); );

View file

@ -341,7 +341,7 @@ class _NameYourWalletViewState extends ConsumerState<NameYourWalletView> {
}); });
} }
}, },
) ),
], ],
), ),
), ),

View file

@ -40,11 +40,11 @@ import 'sub_widgets/mnemonic_table.dart';
class NewWalletRecoveryPhraseView extends ConsumerStatefulWidget { class NewWalletRecoveryPhraseView extends ConsumerStatefulWidget {
const NewWalletRecoveryPhraseView({ const NewWalletRecoveryPhraseView({
Key? key, super.key,
required this.wallet, required this.wallet,
required this.mnemonic, required this.mnemonic,
this.clipboardInterface = const ClipboardWrapper(), this.clipboardInterface = const ClipboardWrapper(),
}) : super(key: key); });
static const routeName = "/newWalletRecoveryPhrase"; static const routeName = "/newWalletRecoveryPhrase";
@ -91,12 +91,14 @@ class _NewWalletRecoveryPhraseViewState
Future<void> _copy() async { Future<void> _copy() async {
final words = _mnemonic; final words = _mnemonic;
await _clipboardInterface.setData(ClipboardData(text: words.join(" "))); await _clipboardInterface.setData(ClipboardData(text: words.join(" ")));
unawaited(showFloatingFlushBar( unawaited(
type: FlushBarType.info, showFloatingFlushBar(
message: "Copied to clipboard", type: FlushBarType.info,
iconAsset: Assets.svg.copy, message: "Copied to clipboard",
context: context, iconAsset: Assets.svg.copy,
)); context: context,
),
);
} }
@override @override
@ -238,7 +240,8 @@ class _NewWalletRecoveryPhraseViewState
.background .background
: Theme.of(context).extension<StackColors>()!.popupBG, : Theme.of(context).extension<StackColors>()!.popupBG,
borderRadius: BorderRadius.circular( borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius), Constants.size.circularBorderRadius,
),
), ),
child: Padding( child: Padding(
padding: isDesktop padding: isDesktop
@ -252,7 +255,8 @@ class _NewWalletRecoveryPhraseViewState
: STextStyles.label(context).copyWith( : STextStyles.label(context).copyWith(
color: Theme.of(context) color: Theme.of(context)
.extension<StackColors>()! .extension<StackColors>()!
.accentColorDark), .accentColorDark,
),
), ),
), ),
), ),
@ -300,8 +304,9 @@ class _NewWalletRecoveryPhraseViewState
Text( Text(
"Copy to clipboard", "Copy to clipboard",
style: STextStyles.desktopButtonSecondaryEnabled( style: STextStyles.desktopButtonSecondaryEnabled(
context), context,
) ),
),
], ],
), ),
), ),
@ -325,10 +330,12 @@ class _NewWalletRecoveryPhraseViewState
.read(verifyMnemonicCorrectWordStateProvider.state) .read(verifyMnemonicCorrectWordStateProvider.state)
.update((state) => _mnemonic[next]); .update((state) => _mnemonic[next]);
unawaited(Navigator.of(context).pushNamed( unawaited(
VerifyRecoveryPhraseView.routeName, Navigator.of(context).pushNamed(
arguments: Tuple2(_wallet, _mnemonic), VerifyRecoveryPhraseView.routeName,
)); arguments: Tuple2(_wallet, _mnemonic),
),
);
}, },
style: Theme.of(context) style: Theme.of(context)
.extension<StackColors>()! .extension<StackColors>()!

View file

@ -13,11 +13,11 @@ import 'mnemonic_table_item.dart';
class MnemonicTable extends StatelessWidget { class MnemonicTable extends StatelessWidget {
const MnemonicTable({ const MnemonicTable({
Key? key, super.key,
required this.words, required this.words,
required this.isDesktop, required this.isDesktop,
this.itemBorderColor, this.itemBorderColor,
}) : super(key: key); });
final List<String> words; final List<String> words;
final bool isDesktop; final bool isDesktop;

View file

@ -15,12 +15,12 @@ import '../../../../widgets/rounded_white_container.dart';
class MnemonicTableItem extends StatelessWidget { class MnemonicTableItem extends StatelessWidget {
const MnemonicTableItem({ const MnemonicTableItem({
Key? key, super.key,
required this.number, required this.number,
required this.word, required this.word,
required this.isDesktop, required this.isDesktop,
this.borderColor, this.borderColor,
}) : super(key: key); });
final int number; final int number;
final String word; final String word;

View file

@ -14,7 +14,7 @@ import '../../../widgets/desktop/secondary_button.dart';
import '../../../widgets/stack_dialog.dart'; import '../../../widgets/stack_dialog.dart';
class RecoveryPhraseExplanationDialog extends StatelessWidget { class RecoveryPhraseExplanationDialog extends StatelessWidget {
const RecoveryPhraseExplanationDialog({Key? key}) : super(key: key); const RecoveryPhraseExplanationDialog({super.key});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {

View file

@ -21,8 +21,7 @@ import '../../../widgets/desktop/secondary_button.dart';
import '../../../widgets/stack_dialog.dart'; import '../../../widgets/stack_dialog.dart';
class ConfirmRecoveryDialog extends StatelessWidget { class ConfirmRecoveryDialog extends StatelessWidget {
const ConfirmRecoveryDialog({Key? key, required this.onConfirm}) const ConfirmRecoveryDialog({super.key, required this.onConfirm});
: super(key: key);
final VoidCallback onConfirm; final VoidCallback onConfirm;
@ -85,10 +84,10 @@ class ConfirmRecoveryDialog extends StatelessWidget {
onConfirm.call(); onConfirm.call();
}, },
), ),
) ),
], ],
), ),
) ),
], ],
), ),
); );

View file

@ -12,13 +12,8 @@ import 'package:dropdown_button2/dropdown_button2.dart';
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:flutter_svg/svg.dart'; import 'package:flutter_svg/svg.dart';
import '../../create_or_restore_wallet_view/sub_widgets/coin_image.dart'; import 'package:tuple/tuple.dart';
import 'sub_widgets/mobile_mnemonic_length_selector.dart';
import 'sub_widgets/restore_from_date_picker.dart';
import 'sub_widgets/restore_options_next_button.dart';
import 'sub_widgets/restore_options_platform_layout.dart';
import '../restore_wallet_view.dart';
import '../sub_widgets/mnemonic_word_count_select_sheet.dart';
import '../../../../pages_desktop_specific/my_stack_view/exit_to_my_stack_button.dart'; import '../../../../pages_desktop_specific/my_stack_view/exit_to_my_stack_button.dart';
import '../../../../providers/ui/verify_recovery_phrase/mnemonic_word_count_state_provider.dart'; import '../../../../providers/ui/verify_recovery_phrase/mnemonic_word_count_state_provider.dart';
import '../../../../themes/stack_colors.dart'; import '../../../../themes/stack_colors.dart';
@ -27,19 +22,23 @@ import '../../../../utilities/constants.dart';
import '../../../../utilities/format.dart'; import '../../../../utilities/format.dart';
import '../../../../utilities/text_styles.dart'; import '../../../../utilities/text_styles.dart';
import '../../../../utilities/util.dart'; import '../../../../utilities/util.dart';
import '../../../../wallets/crypto_currency/coins/epiccash.dart';
import '../../../../wallets/crypto_currency/coins/monero.dart';
import '../../../../wallets/crypto_currency/coins/wownero.dart';
import '../../../../wallets/crypto_currency/crypto_currency.dart'; import '../../../../wallets/crypto_currency/crypto_currency.dart';
import '../../../../widgets/conditional_parent.dart'; import '../../../../widgets/conditional_parent.dart';
import '../../../../widgets/custom_buttons/app_bar_icon_button.dart'; import '../../../../widgets/custom_buttons/app_bar_icon_button.dart';
import '../../../../widgets/custom_buttons/checkbox_text_button.dart';
import '../../../../widgets/date_picker/date_picker.dart'; import '../../../../widgets/date_picker/date_picker.dart';
import '../../../../widgets/desktop/desktop_app_bar.dart'; import '../../../../widgets/desktop/desktop_app_bar.dart';
import '../../../../widgets/desktop/desktop_scaffold.dart'; import '../../../../widgets/desktop/desktop_scaffold.dart';
import '../../../../widgets/expandable.dart'; import '../../../../widgets/expandable.dart';
import '../../../../widgets/rounded_white_container.dart'; import '../../../../widgets/rounded_white_container.dart';
import '../../../../widgets/stack_text_field.dart'; import '../../../../widgets/stack_text_field.dart';
import 'package:tuple/tuple.dart'; import '../../create_or_restore_wallet_view/sub_widgets/coin_image.dart';
import '../restore_wallet_view.dart';
import '../sub_widgets/mnemonic_word_count_select_sheet.dart';
import 'sub_widgets/mobile_mnemonic_length_selector.dart';
import 'sub_widgets/restore_from_date_picker.dart';
import 'sub_widgets/restore_options_next_button.dart';
import 'sub_widgets/restore_options_platform_layout.dart';
class RestoreOptionsView extends ConsumerStatefulWidget { class RestoreOptionsView extends ConsumerStatefulWidget {
const RestoreOptionsView({ const RestoreOptionsView({
@ -74,6 +73,9 @@ class _RestoreOptionsViewState extends ConsumerState<RestoreOptionsView> {
bool get supportsMnemonicPassphrase => coin.hasMnemonicPassphraseSupport; bool get supportsMnemonicPassphrase => coin.hasMnemonicPassphraseSupport;
bool enableLelantusScanning = false;
bool get supportsLelantus => coin is Firo;
@override @override
void initState() { void initState() {
walletName = widget.walletName; walletName = widget.walletName;
@ -109,12 +111,13 @@ class _RestoreOptionsViewState extends ConsumerState<RestoreOptionsView> {
if (mounted) { if (mounted) {
await Navigator.of(context).pushNamed( await Navigator.of(context).pushNamed(
RestoreWalletView.routeName, RestoreWalletView.routeName,
arguments: Tuple5( arguments: Tuple6(
walletName, walletName,
coin, coin,
ref.read(mnemonicWordCountStateProvider.state).state, ref.read(mnemonicWordCountStateProvider.state).state,
_restoreFromDate, _restoreFromDate,
passwordController.text, passwordController.text,
enableLelantusScanning,
), ),
); );
} }
@ -219,7 +222,9 @@ class _RestoreOptionsViewState extends ConsumerState<RestoreOptionsView> {
SizedBox( SizedBox(
height: isDesktop ? 40 : 24, height: isDesktop ? 40 : 24,
), ),
if (coin is Monero || if ((coin is Monero &&
ref.watch(mnemonicWordCountStateProvider.state).state ==
25) ||
coin is Epiccash || coin is Epiccash ||
(coin is Wownero && (coin is Wownero &&
ref.watch(mnemonicWordCountStateProvider.state).state == ref.watch(mnemonicWordCountStateProvider.state).state ==
@ -235,7 +240,9 @@ class _RestoreOptionsViewState extends ConsumerState<RestoreOptionsView> {
: STextStyles.smallMed12(context), : STextStyles.smallMed12(context),
textAlign: TextAlign.left, textAlign: TextAlign.left,
), ),
if (coin is Monero || if ((coin is Monero &&
ref.watch(mnemonicWordCountStateProvider.state).state ==
25) ||
coin is Epiccash || coin is Epiccash ||
(coin is Wownero && (coin is Wownero &&
ref.watch(mnemonicWordCountStateProvider.state).state == ref.watch(mnemonicWordCountStateProvider.state).state ==
@ -243,7 +250,9 @@ class _RestoreOptionsViewState extends ConsumerState<RestoreOptionsView> {
SizedBox( SizedBox(
height: isDesktop ? 16 : 8, height: isDesktop ? 16 : 8,
), ),
if (coin is Monero || if ((coin is Monero &&
ref.watch(mnemonicWordCountStateProvider.state).state ==
25) ||
coin is Epiccash || coin is Epiccash ||
(coin is Wownero && (coin is Wownero &&
ref.watch(mnemonicWordCountStateProvider.state).state == ref.watch(mnemonicWordCountStateProvider.state).state ==
@ -253,7 +262,9 @@ class _RestoreOptionsViewState extends ConsumerState<RestoreOptionsView> {
onTap: chooseDate, onTap: chooseDate,
controller: _dateController, controller: _dateController,
), ),
if (coin is Monero || if ((coin is Monero &&
ref.watch(mnemonicWordCountStateProvider.state).state ==
25) ||
coin is Epiccash || coin is Epiccash ||
(coin is Wownero && (coin is Wownero &&
ref.watch(mnemonicWordCountStateProvider.state).state == ref.watch(mnemonicWordCountStateProvider.state).state ==
@ -264,7 +275,9 @@ class _RestoreOptionsViewState extends ConsumerState<RestoreOptionsView> {
onTap: chooseDesktopDate, onTap: chooseDesktopDate,
controller: _dateController, controller: _dateController,
), ),
if (coin is Monero || if ((coin is Monero &&
ref.watch(mnemonicWordCountStateProvider.state).state ==
25) ||
coin is Epiccash || coin is Epiccash ||
(coin is Wownero && (coin is Wownero &&
ref.watch(mnemonicWordCountStateProvider.state).state == ref.watch(mnemonicWordCountStateProvider.state).state ==
@ -272,7 +285,9 @@ class _RestoreOptionsViewState extends ConsumerState<RestoreOptionsView> {
const SizedBox( const SizedBox(
height: 8, height: 8,
), ),
if (coin is Monero || if ((coin is Monero &&
ref.watch(mnemonicWordCountStateProvider.state).state ==
25) ||
coin is Epiccash || coin is Epiccash ||
(coin is Wownero && (coin is Wownero &&
ref.watch(mnemonicWordCountStateProvider.state).state == ref.watch(mnemonicWordCountStateProvider.state).state ==
@ -293,7 +308,9 @@ class _RestoreOptionsViewState extends ConsumerState<RestoreOptionsView> {
), ),
), ),
), ),
if (coin is Monero || if ((coin is Monero &&
ref.watch(mnemonicWordCountStateProvider.state).state ==
25) ||
coin is Epiccash || coin is Epiccash ||
(coin is Wownero && (coin is Wownero &&
ref.watch(mnemonicWordCountStateProvider.state).state == ref.watch(mnemonicWordCountStateProvider.state).state ==
@ -398,8 +415,8 @@ class _RestoreOptionsViewState extends ConsumerState<RestoreOptionsView> {
"Advanced", "Advanced",
style: isDesktop style: isDesktop
? STextStyles.desktopTextExtraExtraSmall( ? STextStyles.desktopTextExtraExtraSmall(
context) context,
.copyWith( ).copyWith(
color: Theme.of(context) color: Theme.of(context)
.extension<StackColors>()! .extension<StackColors>()!
.textDark3, .textDark3,
@ -425,6 +442,17 @@ class _RestoreOptionsViewState extends ConsumerState<RestoreOptionsView> {
color: Colors.transparent, color: Colors.transparent,
child: Column( child: Column(
children: [ children: [
CheckboxTextButton(
label: "Scan for Lelantus transactions",
onChanged: (newValue) {
setState(() {
enableLelantusScanning = newValue ?? true;
});
},
),
const SizedBox(
height: 8,
),
ClipRRect( ClipRRect(
borderRadius: BorderRadius.circular( borderRadius: BorderRadius.circular(
Constants.size.circularBorderRadius, Constants.size.circularBorderRadius,
@ -461,7 +489,8 @@ class _RestoreOptionsViewState extends ConsumerState<RestoreOptionsView> {
), ),
GestureDetector( GestureDetector(
key: const Key( key: const Key(
"mnemonicPassphraseFieldShowPasswordButtonKey"), "mnemonicPassphraseFieldShowPasswordButtonKey",
),
onTap: () async { onTap: () async {
setState(() { setState(() {
hidePassword = !hidePassword; hidePassword = !hidePassword;

View file

@ -20,9 +20,9 @@ import '../../../../../utilities/util.dart';
class MobileMnemonicLengthSelector extends ConsumerWidget { class MobileMnemonicLengthSelector extends ConsumerWidget {
const MobileMnemonicLengthSelector({ const MobileMnemonicLengthSelector({
Key? key, super.key,
required this.chooseMnemonicLength, required this.chooseMnemonicLength,
}) : super(key: key); });
final VoidCallback chooseMnemonicLength; final VoidCallback chooseMnemonicLength;
@ -66,7 +66,7 @@ class MobileMnemonicLengthSelector extends ConsumerWidget {
], ],
), ),
), ),
) ),
], ],
); );
} }

View file

@ -17,10 +17,10 @@ import '../../../../../utilities/util.dart';
class RestoreFromDatePicker extends StatefulWidget { class RestoreFromDatePicker extends StatefulWidget {
const RestoreFromDatePicker({ const RestoreFromDatePicker({
Key? key, super.key,
required this.onTap, required this.onTap,
required this.controller, required this.controller,
}) : super(key: key); });
final VoidCallback onTap; final VoidCallback onTap;
final TextEditingController controller; final TextEditingController controller;

View file

@ -14,10 +14,10 @@ import '../../../../../utilities/text_styles.dart';
class RestoreOptionsNextButton extends StatelessWidget { class RestoreOptionsNextButton extends StatelessWidget {
const RestoreOptionsNextButton({ const RestoreOptionsNextButton({
Key? key, super.key,
required this.isDesktop, required this.isDesktop,
this.onPressed, this.onPressed,
}) : super(key: key); });
final bool isDesktop; final bool isDesktop;
final VoidCallback? onPressed; final VoidCallback? onPressed;

View file

@ -13,10 +13,10 @@ import '../../../../../themes/stack_colors.dart';
class RestoreOptionsPlatformLayout extends StatelessWidget { class RestoreOptionsPlatformLayout extends StatelessWidget {
const RestoreOptionsPlatformLayout({ const RestoreOptionsPlatformLayout({
Key? key, super.key,
required this.isDesktop, required this.isDesktop,
required this.child, required this.child,
}) : super(key: key); });
final bool isDesktop; final bool isDesktop;
final Widget child; final Widget child;

View file

@ -22,15 +22,9 @@ import 'package:flutter_libmonero/monero/monero.dart' as libxmr;
import 'package:flutter_libmonero/wownero/wownero.dart' as libwow; import 'package:flutter_libmonero/wownero/wownero.dart' as libwow;
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
import 'package:wakelock/wakelock.dart';
import '../../../notifications/show_flush_bar.dart'; import '../../../notifications/show_flush_bar.dart';
import '../add_token_view/edit_wallet_tokens_view.dart';
import 'confirm_recovery_dialog.dart';
import 'sub_widgets/restore_failed_dialog.dart';
import 'sub_widgets/restore_succeeded_dialog.dart';
import 'sub_widgets/restoring_dialog.dart';
import '../select_wallet_for_token_view.dart';
import '../verify_recovery_phrase_view/verify_recovery_phrase_view.dart';
import '../../home_view/home_view.dart';
import '../../../pages_desktop_specific/desktop_home_view.dart'; import '../../../pages_desktop_specific/desktop_home_view.dart';
import '../../../pages_desktop_specific/my_stack_view/exit_to_my_stack_button.dart'; import '../../../pages_desktop_specific/my_stack_view/exit_to_my_stack_button.dart';
import '../../../providers/db/main_db_provider.dart'; import '../../../providers/db/main_db_provider.dart';
@ -48,11 +42,6 @@ import '../../../utilities/enums/form_input_status_enum.dart';
import '../../../utilities/logger.dart'; import '../../../utilities/logger.dart';
import '../../../utilities/text_styles.dart'; import '../../../utilities/text_styles.dart';
import '../../../utilities/util.dart'; import '../../../utilities/util.dart';
import '../../../wallets/crypto_currency/coins/epiccash.dart';
import '../../../wallets/crypto_currency/coins/ethereum.dart';
import '../../../wallets/crypto_currency/coins/firo.dart';
import '../../../wallets/crypto_currency/coins/monero.dart';
import '../../../wallets/crypto_currency/coins/wownero.dart';
import '../../../wallets/crypto_currency/crypto_currency.dart'; import '../../../wallets/crypto_currency/crypto_currency.dart';
import '../../../wallets/isar/models/wallet_info.dart'; import '../../../wallets/isar/models/wallet_info.dart';
import '../../../wallets/wallet/impl/epiccash_wallet.dart'; import '../../../wallets/wallet/impl/epiccash_wallet.dart';
@ -69,7 +58,14 @@ import '../../../widgets/icon_widgets/qrcode_icon.dart';
import '../../../widgets/table_view/table_view.dart'; import '../../../widgets/table_view/table_view.dart';
import '../../../widgets/table_view/table_view_cell.dart'; import '../../../widgets/table_view/table_view_cell.dart';
import '../../../widgets/table_view/table_view_row.dart'; import '../../../widgets/table_view/table_view_row.dart';
import 'package:wakelock/wakelock.dart'; import '../../home_view/home_view.dart';
import '../add_token_view/edit_wallet_tokens_view.dart';
import '../select_wallet_for_token_view.dart';
import '../verify_recovery_phrase_view/verify_recovery_phrase_view.dart';
import 'confirm_recovery_dialog.dart';
import 'sub_widgets/restore_failed_dialog.dart';
import 'sub_widgets/restore_succeeded_dialog.dart';
import 'sub_widgets/restoring_dialog.dart';
class RestoreWalletView extends ConsumerStatefulWidget { class RestoreWalletView extends ConsumerStatefulWidget {
const RestoreWalletView({ const RestoreWalletView({
@ -79,6 +75,7 @@ class RestoreWalletView extends ConsumerStatefulWidget {
required this.seedWordsLength, required this.seedWordsLength,
required this.mnemonicPassphrase, required this.mnemonicPassphrase,
required this.restoreFromDate, required this.restoreFromDate,
this.enableLelantusScanning = false,
this.barcodeScanner = const BarcodeScannerWrapper(), this.barcodeScanner = const BarcodeScannerWrapper(),
this.clipboard = const ClipboardWrapper(), this.clipboard = const ClipboardWrapper(),
}); });
@ -90,6 +87,7 @@ class RestoreWalletView extends ConsumerStatefulWidget {
final String mnemonicPassphrase; final String mnemonicPassphrase;
final int seedWordsLength; final int seedWordsLength;
final DateTime restoreFromDate; final DateTime restoreFromDate;
final bool enableLelantusScanning;
final BarcodeScannerInterface barcodeScanner; final BarcodeScannerInterface barcodeScanner;
final ClipboardInterface clipboard; final ClipboardInterface clipboard;
@ -261,6 +259,8 @@ class _RestoreWalletViewState extends ConsumerState<RestoreWalletView> {
otherDataJsonString = jsonEncode( otherDataJsonString = jsonEncode(
{ {
WalletInfoKeys.lelantusCoinIsarRescanRequired: false, WalletInfoKeys.lelantusCoinIsarRescanRequired: false,
WalletInfoKeys.enableLelantusScanning:
widget.enableLelantusScanning,
}, },
); );
} }

View file

@ -10,6 +10,7 @@
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 '../../../../providers/ui/verify_recovery_phrase/mnemonic_word_count_state_provider.dart'; import '../../../../providers/ui/verify_recovery_phrase/mnemonic_word_count_state_provider.dart';
import '../../../../themes/stack_colors.dart'; import '../../../../themes/stack_colors.dart';
import '../../../../utilities/constants.dart'; import '../../../../utilities/constants.dart';
@ -17,9 +18,9 @@ import '../../../../utilities/text_styles.dart';
class MnemonicWordCountSelectSheet extends ConsumerWidget { class MnemonicWordCountSelectSheet extends ConsumerWidget {
const MnemonicWordCountSelectSheet({ const MnemonicWordCountSelectSheet({
Key? key, super.key,
required this.lengthOptions, required this.lengthOptions,
}) : super(key: key); });
final List<int> lengthOptions; final List<int> lengthOptions;
@ -113,13 +114,16 @@ class MnemonicWordCountSelectSheet extends ConsumerWidget {
.radioButtonIconEnabled, .radioButtonIconEnabled,
value: lengthOptions[i], value: lengthOptions[i],
groupValue: ref groupValue: ref
.watch(mnemonicWordCountStateProvider .watch(
.state) mnemonicWordCountStateProvider.state,
)
.state, .state,
onChanged: (x) { onChanged: (x) {
ref ref
.read(mnemonicWordCountStateProvider .read(
.state) mnemonicWordCountStateProvider
.state,
)
.state = lengthOptions[i]; .state = lengthOptions[i];
Navigator.of(context).pop(); Navigator.of(context).pop();
}, },

View file

@ -20,11 +20,11 @@ import '../../../../widgets/stack_dialog.dart';
class RestoreFailedDialog extends ConsumerStatefulWidget { class RestoreFailedDialog extends ConsumerStatefulWidget {
const RestoreFailedDialog({ const RestoreFailedDialog({
Key? key, super.key,
required this.errorMessage, required this.errorMessage,
required this.walletName, required this.walletName,
required this.walletId, required this.walletId,
}) : super(key: key); });
final String errorMessage; final String errorMessage;
final String walletName; final String walletName;

View file

@ -20,7 +20,7 @@ import '../../../../widgets/desktop/primary_button.dart';
import '../../../../widgets/stack_dialog.dart'; import '../../../../widgets/stack_dialog.dart';
class RestoreSucceededDialog extends StatelessWidget { class RestoreSucceededDialog extends StatelessWidget {
const RestoreSucceededDialog({Key? key}) : super(key: key); const RestoreSucceededDialog({super.key});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {

View file

@ -20,9 +20,9 @@ import '../../../../widgets/stack_dialog.dart';
class RestoringDialog extends StatefulWidget { class RestoringDialog extends StatefulWidget {
const RestoringDialog({ const RestoringDialog({
Key? key, super.key,
required this.onCancel, required this.onCancel,
}) : super(key: key); });
final Future<void> Function() onCancel; final Future<void> Function() onCancel;

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