This commit is contained in:
Matthew Fosse 2024-04-15 12:01:27 -07:00
commit 77bf710a5f
120 changed files with 4164 additions and 811 deletions

BIN
.github/assets/Logo_CakeWallet.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 156 KiB

48
.github/assets/NOTICE.txt vendored Normal file
View file

@ -0,0 +1,48 @@
Notice for linux-badge.svg:
1:
This is the Linux-penguin again...
Originally drewn by Larry Ewing (http://www.isc.tamu.edu/~lewing/)
(with the GIMP) the Linux Logo has been vectorized by me (Simon Budig,
http://www.home.unix-ag.org/simon/).
This happened quite some time ago with Corel Draw 4. But luckily
meanwhile there are tools available to handle vector graphics with
Linux. Bernhard Herzog (bernhard@users.sourceforge.net) deserves kudos
for creating Sketch (http://sketch.sourceforge.net), a powerful free
tool for creating vector graphics. He converted the Corel Draw file to
the Sketch native format. Since I am unable to maintain the Corel Draw
file any longer, the Sketch version now is the "official" one.
Anja Gerwinski (anja@gerwinski.de) has created an alternate version of
the penguin (penguin-variant.sk) with a thinner mouth line and slightly
altered gradients. It also features a nifty drop shadow.
The third bird (penguin-flat.sk) is a version reduced to three colors
(black/white/yellow) for e.g. silk screen printing. I made this version
for a mug, available at the friendly folks at
http://www.kernelconcepts.de/ - they do good stuff, mail Petra
(pinguin@kernelconcepts.de) if you need something special or don't
understand the german :-)
These drawings are copyrighted by Larry Ewing and Simon Budig
(penguin-variant.sk also by Anja Gerwinski), redistribution is free but
has to include this README/Copyright notice.
The use of these drawings is free. However I am happy about a sample of
your mug/t-shirt/whatever with this penguin on it...
Have fun
Simon Budig
Simon.Budig@unix-ag.org
http://www.home.unix-ag.org/simon/
Simon Budig
Am Hardtkoeppel 2
D-61279 Graevenwiesbach
2:
Attribution: lewing@isc.tamu.edu Larry Ewing and The GIMP

46
.github/assets/app-store-badge.svg vendored Executable file
View file

@ -0,0 +1,46 @@
<svg id="livetype" xmlns="http://www.w3.org/2000/svg" width="119.66407" height="40" viewBox="0 0 119.66407 40">
<title>Download_on_the_App_Store_Badge_US-UK_RGB_blk_4SVG_092917</title>
<g>
<g>
<g>
<path d="M110.13477,0H9.53468c-.3667,0-.729,0-1.09473.002-.30615.002-.60986.00781-.91895.0127A13.21476,13.21476,0,0,0,5.5171.19141a6.66509,6.66509,0,0,0-1.90088.627A6.43779,6.43779,0,0,0,1.99757,1.99707,6.25844,6.25844,0,0,0,.81935,3.61816a6.60119,6.60119,0,0,0-.625,1.90332,12.993,12.993,0,0,0-.1792,2.002C.00587,7.83008.00489,8.1377,0,8.44434V31.5586c.00489.3105.00587.6113.01515.9219a12.99232,12.99232,0,0,0,.1792,2.0019,6.58756,6.58756,0,0,0,.625,1.9043A6.20778,6.20778,0,0,0,1.99757,38.001a6.27445,6.27445,0,0,0,1.61865,1.1787,6.70082,6.70082,0,0,0,1.90088.6308,13.45514,13.45514,0,0,0,2.0039.1768c.30909.0068.6128.0107.91895.0107C8.80567,40,9.168,40,9.53468,40H110.13477c.3594,0,.7246,0,1.084-.002.3047,0,.6172-.0039.9219-.0107a13.279,13.279,0,0,0,2-.1768,6.80432,6.80432,0,0,0,1.9082-.6308,6.27742,6.27742,0,0,0,1.6172-1.1787,6.39482,6.39482,0,0,0,1.1816-1.6143,6.60413,6.60413,0,0,0,.6191-1.9043,13.50643,13.50643,0,0,0,.1856-2.0019c.0039-.3106.0039-.6114.0039-.9219.0078-.3633.0078-.7246.0078-1.0938V9.53613c0-.36621,0-.72949-.0078-1.09179,0-.30664,0-.61426-.0039-.9209a13.5071,13.5071,0,0,0-.1856-2.002,6.6177,6.6177,0,0,0-.6191-1.90332,6.46619,6.46619,0,0,0-2.7988-2.7998,6.76754,6.76754,0,0,0-1.9082-.627,13.04394,13.04394,0,0,0-2-.17676c-.3047-.00488-.6172-.01074-.9219-.01269-.3594-.002-.7246-.002-1.084-.002Z" style="fill: #a6a6a6"/>
<path d="M8.44483,39.125c-.30468,0-.602-.0039-.90429-.0107a12.68714,12.68714,0,0,1-1.86914-.1631,5.88381,5.88381,0,0,1-1.65674-.5479,5.40573,5.40573,0,0,1-1.397-1.0166,5.32082,5.32082,0,0,1-1.02051-1.3965,5.72186,5.72186,0,0,1-.543-1.6572,12.41351,12.41351,0,0,1-.1665-1.875c-.00634-.2109-.01464-.9131-.01464-.9131V8.44434S.88185,7.75293.8877,7.5498a12.37039,12.37039,0,0,1,.16553-1.87207,5.7555,5.7555,0,0,1,.54346-1.6621A5.37349,5.37349,0,0,1,2.61183,2.61768,5.56543,5.56543,0,0,1,4.01417,1.59521a5.82309,5.82309,0,0,1,1.65332-.54394A12.58589,12.58589,0,0,1,7.543.88721L8.44532.875H111.21387l.9131.0127a12.38493,12.38493,0,0,1,1.8584.16259,5.93833,5.93833,0,0,1,1.6709.54785,5.59374,5.59374,0,0,1,2.415,2.41993,5.76267,5.76267,0,0,1,.5352,1.64892,12.995,12.995,0,0,1,.1738,1.88721c.0029.2832.0029.5874.0029.89014.0079.375.0079.73193.0079,1.09179V30.4648c0,.3633,0,.7178-.0079,1.0752,0,.3252,0,.6231-.0039.9297a12.73126,12.73126,0,0,1-.1709,1.8535,5.739,5.739,0,0,1-.54,1.67,5.48029,5.48029,0,0,1-1.0156,1.3857,5.4129,5.4129,0,0,1-1.3994,1.0225,5.86168,5.86168,0,0,1-1.668.5498,12.54218,12.54218,0,0,1-1.8692.1631c-.2929.0068-.5996.0107-.8974.0107l-1.084.002Z"/>
</g>
<g id="_Group_" data-name="&lt;Group&gt;">
<g id="_Group_2" data-name="&lt;Group&gt;">
<g id="_Group_3" data-name="&lt;Group&gt;">
<path id="_Path_" data-name="&lt;Path&gt;" d="M24.76888,20.30068a4.94881,4.94881,0,0,1,2.35656-4.15206,5.06566,5.06566,0,0,0-3.99116-2.15768c-1.67924-.17626-3.30719,1.00483-4.1629,1.00483-.87227,0-2.18977-.98733-3.6085-.95814a5.31529,5.31529,0,0,0-4.47292,2.72787c-1.934,3.34842-.49141,8.26947,1.3612,10.97608.9269,1.32535,2.01018,2.8058,3.42763,2.7533,1.38706-.05753,1.9051-.88448,3.5794-.88448,1.65876,0,2.14479.88448,3.591.8511,1.48838-.02416,2.42613-1.33124,3.32051-2.66914a10.962,10.962,0,0,0,1.51842-3.09251A4.78205,4.78205,0,0,1,24.76888,20.30068Z" style="fill: #fff"/>
<path id="_Path_2" data-name="&lt;Path&gt;" d="M22.03725,12.21089a4.87248,4.87248,0,0,0,1.11452-3.49062,4.95746,4.95746,0,0,0-3.20758,1.65961,4.63634,4.63634,0,0,0-1.14371,3.36139A4.09905,4.09905,0,0,0,22.03725,12.21089Z" style="fill: #fff"/>
</g>
</g>
<g>
<path d="M42.30227,27.13965h-4.7334l-1.13672,3.35645H34.42727l4.4834-12.418h2.083l4.4834,12.418H43.438ZM38.0591,25.59082h3.752l-1.84961-5.44727h-.05176Z" style="fill: #fff"/>
<path d="M55.15969,25.96973c0,2.81348-1.50586,4.62109-3.77832,4.62109a3.0693,3.0693,0,0,1-2.84863-1.584h-.043v4.48438h-1.8584V21.44238H48.4302v1.50586h.03418a3.21162,3.21162,0,0,1,2.88281-1.60059C53.645,21.34766,55.15969,23.16406,55.15969,25.96973Zm-1.91016,0c0-1.833-.94727-3.03809-2.39258-3.03809-1.41992,0-2.375,1.23047-2.375,3.03809,0,1.82422.95508,3.0459,2.375,3.0459C52.30227,29.01563,53.24953,27.81934,53.24953,25.96973Z" style="fill: #fff"/>
<path d="M65.12453,25.96973c0,2.81348-1.50586,4.62109-3.77832,4.62109a3.0693,3.0693,0,0,1-2.84863-1.584h-.043v4.48438h-1.8584V21.44238H58.395v1.50586h.03418A3.21162,3.21162,0,0,1,61.312,21.34766C63.60988,21.34766,65.12453,23.16406,65.12453,25.96973Zm-1.91016,0c0-1.833-.94727-3.03809-2.39258-3.03809-1.41992,0-2.375,1.23047-2.375,3.03809,0,1.82422.95508,3.0459,2.375,3.0459C62.26711,29.01563,63.21438,27.81934,63.21438,25.96973Z" style="fill: #fff"/>
<path d="M71.71047,27.03613c.1377,1.23145,1.334,2.04,2.96875,2.04,1.56641,0,2.69336-.80859,2.69336-1.91895,0-.96387-.67969-1.541-2.28906-1.93652l-1.60937-.3877c-2.28027-.55078-3.33887-1.61719-3.33887-3.34766,0-2.14258,1.86719-3.61426,4.51855-3.61426,2.624,0,4.42285,1.47168,4.4834,3.61426h-1.876c-.1123-1.23926-1.13672-1.9873-2.63379-1.9873s-2.52148.75684-2.52148,1.8584c0,.87793.6543,1.39453,2.25488,1.79l1.36816.33594c2.54785.60254,3.60645,1.626,3.60645,3.44238,0,2.32324-1.85059,3.77832-4.79395,3.77832-2.75391,0-4.61328-1.4209-4.7334-3.667Z" style="fill: #fff"/>
<path d="M83.34621,19.2998v2.14258h1.72168v1.47168H83.34621v4.99121c0,.77539.34473,1.13672,1.10156,1.13672a5.80752,5.80752,0,0,0,.61133-.043v1.46289a5.10351,5.10351,0,0,1-1.03223.08594c-1.833,0-2.54785-.68848-2.54785-2.44434V22.91406H80.16262V21.44238H81.479V19.2998Z" style="fill: #fff"/>
<path d="M86.065,25.96973c0-2.84863,1.67773-4.63867,4.29395-4.63867,2.625,0,4.29492,1.79,4.29492,4.63867,0,2.85645-1.66113,4.63867-4.29492,4.63867C87.72609,30.6084,86.065,28.82617,86.065,25.96973Zm6.69531,0c0-1.9541-.89551-3.10742-2.40137-3.10742s-2.40039,1.16211-2.40039,3.10742c0,1.96191.89453,3.10645,2.40039,3.10645S92.76027,27.93164,92.76027,25.96973Z" style="fill: #fff"/>
<path d="M96.18606,21.44238h1.77246v1.541h.043a2.1594,2.1594,0,0,1,2.17773-1.63574,2.86616,2.86616,0,0,1,.63672.06934v1.73828a2.59794,2.59794,0,0,0-.835-.1123,1.87264,1.87264,0,0,0-1.93652,2.083v5.37012h-1.8584Z" style="fill: #fff"/>
<path d="M109.3843,27.83691c-.25,1.64355-1.85059,2.77148-3.89844,2.77148-2.63379,0-4.26855-1.76465-4.26855-4.5957,0-2.83984,1.64355-4.68164,4.19043-4.68164,2.50488,0,4.08008,1.7207,4.08008,4.46582v.63672h-6.39453v.1123a2.358,2.358,0,0,0,2.43555,2.56445,2.04834,2.04834,0,0,0,2.09082-1.27344Zm-6.28223-2.70215h4.52637a2.1773,2.1773,0,0,0-2.2207-2.29785A2.292,2.292,0,0,0,103.10207,25.13477Z" style="fill: #fff"/>
</g>
</g>
</g>
<g id="_Group_4" data-name="&lt;Group&gt;">
<g>
<path d="M37.82619,8.731a2.63964,2.63964,0,0,1,2.80762,2.96484c0,1.90625-1.03027,3.002-2.80762,3.002H35.67092V8.731Zm-1.22852,5.123h1.125a1.87588,1.87588,0,0,0,1.96777-2.146,1.881,1.881,0,0,0-1.96777-2.13379h-1.125Z" style="fill: #fff"/>
<path d="M41.68068,12.44434a2.13323,2.13323,0,1,1,4.24707,0,2.13358,2.13358,0,1,1-4.24707,0Zm3.333,0c0-.97607-.43848-1.54687-1.208-1.54687-.77246,0-1.207.5708-1.207,1.54688,0,.98389.43457,1.55029,1.207,1.55029C44.57522,13.99463,45.01369,13.42432,45.01369,12.44434Z" style="fill: #fff"/>
<path d="M51.57326,14.69775h-.92187l-.93066-3.31641h-.07031l-.92676,3.31641h-.91309l-1.24121-4.50293h.90137l.80664,3.436h.06641l.92578-3.436h.85254l.92578,3.436h.07031l.80273-3.436h.88867Z" style="fill: #fff"/>
<path d="M53.85354,10.19482H54.709v.71533h.06641a1.348,1.348,0,0,1,1.34375-.80225,1.46456,1.46456,0,0,1,1.55859,1.6748v2.915h-.88867V12.00586c0-.72363-.31445-1.0835-.97168-1.0835a1.03294,1.03294,0,0,0-1.0752,1.14111v2.63428h-.88867Z" style="fill: #fff"/>
<path d="M59.09377,8.437h.88867v6.26074h-.88867Z" style="fill: #fff"/>
<path d="M61.21779,12.44434a2.13346,2.13346,0,1,1,4.24756,0,2.1338,2.1338,0,1,1-4.24756,0Zm3.333,0c0-.97607-.43848-1.54687-1.208-1.54687-.77246,0-1.207.5708-1.207,1.54688,0,.98389.43457,1.55029,1.207,1.55029C64.11232,13.99463,64.5508,13.42432,64.5508,12.44434Z" style="fill: #fff"/>
<path d="M66.4009,13.42432c0-.81055.60352-1.27783,1.6748-1.34424l1.21973-.07031v-.38867c0-.47559-.31445-.74414-.92187-.74414-.49609,0-.83984.18213-.93848.50049h-.86035c.09082-.77344.81836-1.26953,1.83984-1.26953,1.12891,0,1.76563.562,1.76563,1.51318v3.07666h-.85547v-.63281h-.07031a1.515,1.515,0,0,1-1.35254.707A1.36026,1.36026,0,0,1,66.4009,13.42432Zm2.89453-.38477v-.37646l-1.09961.07031c-.62012.0415-.90137.25244-.90137.64941,0,.40527.35156.64111.835.64111A1.0615,1.0615,0,0,0,69.29543,13.03955Z" style="fill: #fff"/>
<path d="M71.34816,12.44434c0-1.42285.73145-2.32422,1.86914-2.32422a1.484,1.484,0,0,1,1.38086.79h.06641V8.437h.88867v6.26074h-.85156v-.71143h-.07031a1.56284,1.56284,0,0,1-1.41406.78564C72.0718,14.772,71.34816,13.87061,71.34816,12.44434Zm.918,0c0,.95508.4502,1.52979,1.20313,1.52979.749,0,1.21191-.583,1.21191-1.52588,0-.93848-.46777-1.52979-1.21191-1.52979C72.72121,10.91846,72.26613,11.49707,72.26613,12.44434Z" style="fill: #fff"/>
<path d="M79.23,12.44434a2.13323,2.13323,0,1,1,4.24707,0,2.13358,2.13358,0,1,1-4.24707,0Zm3.333,0c0-.97607-.43848-1.54687-1.208-1.54687-.77246,0-1.207.5708-1.207,1.54688,0,.98389.43457,1.55029,1.207,1.55029C82.12453,13.99463,82.563,13.42432,82.563,12.44434Z" style="fill: #fff"/>
<path d="M84.66945,10.19482h.85547v.71533h.06641a1.348,1.348,0,0,1,1.34375-.80225,1.46456,1.46456,0,0,1,1.55859,1.6748v2.915H87.605V12.00586c0-.72363-.31445-1.0835-.97168-1.0835a1.03294,1.03294,0,0,0-1.0752,1.14111v2.63428h-.88867Z" style="fill: #fff"/>
<path d="M93.51516,9.07373v1.1416h.97559v.74854h-.97559V13.2793c0,.47168.19434.67822.63672.67822a2.96657,2.96657,0,0,0,.33887-.02051v.74023a2.9155,2.9155,0,0,1-.4834.04541c-.98828,0-1.38184-.34766-1.38184-1.21582v-2.543h-.71484v-.74854h.71484V9.07373Z" style="fill: #fff"/>
<path d="M95.70461,8.437h.88086v2.48145h.07031a1.3856,1.3856,0,0,1,1.373-.80664,1.48339,1.48339,0,0,1,1.55078,1.67871v2.90723H98.69v-2.688c0-.71924-.335-1.0835-.96289-1.0835a1.05194,1.05194,0,0,0-1.13379,1.1416v2.62988h-.88867Z" style="fill: #fff"/>
<path d="M104.76125,13.48193a1.828,1.828,0,0,1-1.95117,1.30273A2.04531,2.04531,0,0,1,100.73,12.46045a2.07685,2.07685,0,0,1,2.07617-2.35254c1.25293,0,2.00879.856,2.00879,2.27V12.688h-3.17969v.0498a1.1902,1.1902,0,0,0,1.19922,1.29,1.07934,1.07934,0,0,0,1.07129-.5459Zm-3.126-1.45117h2.27441a1.08647,1.08647,0,0,0-1.1084-1.1665A1.15162,1.15162,0,0,0,101.63527,12.03076Z" style="fill: #fff"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 11 KiB

BIN
.github/assets/devices.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

BIN
.github/assets/f-droid-badge.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
.github/assets/google-play-badge.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

1071
.github/assets/linux-badge.svg vendored Executable file

File diff suppressed because it is too large Load diff

After

Width:  |  Height:  |  Size: 67 KiB

51
.github/assets/mac-store-badge.svg vendored Executable file
View file

@ -0,0 +1,51 @@
<svg id="livetype" xmlns="http://www.w3.org/2000/svg" width="156.10054" height="40" viewBox="0 0 156.10054 40">
<title>Download_on_the_Mac_App_Store_Badge_US-UK_RGB_blk_092917</title>
<g>
<g>
<g>
<path d="M146.57123,0H9.53468c-.3667,0-.729,0-1.09473.002-.30615.002-.60986.00781-.91895.0127A13.21476,13.21476,0,0,0,5.5171.19141a6.66509,6.66509,0,0,0-1.90088.627A6.4378,6.4378,0,0,0,1.99757,1.99707,6.25844,6.25844,0,0,0,.81935,3.61816a6.60119,6.60119,0,0,0-.625,1.90332,12.993,12.993,0,0,0-.1792,2.002C.00587,7.83008.00489,8.1377,0,8.44434V31.5586c.00489.3105.00587.6113.01514.9219a12.99232,12.99232,0,0,0,.1792,2.0019,6.58756,6.58756,0,0,0,.625,1.9043A6.20778,6.20778,0,0,0,1.99757,38.001a6.27446,6.27446,0,0,0,1.61865,1.1787,6.70082,6.70082,0,0,0,1.90088.6308,13.45514,13.45514,0,0,0,2.0039.1768c.30909.0068.6128.0107.91895.0107C8.80567,40,9.168,40,9.53468,40H146.57123c.3594,0,.7246,0,1.084-.002.3047,0,.6172-.0039.9219-.0107a13.279,13.279,0,0,0,2-.1768,6.80432,6.80432,0,0,0,1.9082-.6308,6.27742,6.27742,0,0,0,1.6172-1.1787,6.39482,6.39482,0,0,0,1.1816-1.6143,6.60413,6.60413,0,0,0,.6191-1.9043,13.50643,13.50643,0,0,0,.1856-2.0019c.0039-.3106.0039-.6114.0039-.9219.0078-.3633.0078-.7246.0078-1.0938V9.53613c0-.36621,0-.72949-.0078-1.09179,0-.30664,0-.61426-.0039-.9209a13.5071,13.5071,0,0,0-.1856-2.002,6.6177,6.6177,0,0,0-.6191-1.90332,6.46619,6.46619,0,0,0-2.7988-2.7998,6.76754,6.76754,0,0,0-1.9082-.627,13.04394,13.04394,0,0,0-2-.17676c-.3047-.00488-.6172-.01074-.9219-.01269-.3594-.002-.7246-.002-1.084-.002Z" style="fill: #a6a6a6"/>
<path d="M8.44483,39.125c-.30468,0-.60205-.0039-.90429-.0107a12.68714,12.68714,0,0,1-1.86914-.1631,5.88381,5.88381,0,0,1-1.65674-.5479,5.40573,5.40573,0,0,1-1.397-1.0166,5.32082,5.32082,0,0,1-1.02051-1.3965,5.72184,5.72184,0,0,1-.543-1.6572,12.41339,12.41339,0,0,1-.1665-1.875c-.00634-.2109-.01464-.9131-.01464-.9131V8.44434S.88185,7.75293.8877,7.5498a12.37032,12.37032,0,0,1,.16553-1.87207,5.75552,5.75552,0,0,1,.54346-1.6621A5.3735,5.3735,0,0,1,2.61183,2.61768,5.56543,5.56543,0,0,1,4.01417,1.59521a5.82309,5.82309,0,0,1,1.65332-.54394A12.58589,12.58589,0,0,1,7.543.88721L8.44532.875h139.205l.9131.0127a12.38493,12.38493,0,0,1,1.8584.16259,5.93833,5.93833,0,0,1,1.6709.54785,5.59374,5.59374,0,0,1,2.415,2.41993,5.76267,5.76267,0,0,1,.5352,1.64892,12.995,12.995,0,0,1,.1738,1.88721c.0029.2832.0029.5874.0029.89014.0079.375.0079.73193.0079,1.09179V30.4648c0,.3633,0,.7178-.0079,1.0752,0,.3252,0,.6231-.0039.9297a12.73127,12.73127,0,0,1-.1709,1.8535,5.739,5.739,0,0,1-.54,1.67,5.48029,5.48029,0,0,1-1.0156,1.3857,5.4129,5.4129,0,0,1-1.3994,1.0225,5.86168,5.86168,0,0,1-1.668.5498,12.54218,12.54218,0,0,1-1.8692.1631c-.2929.0068-.5996.0107-.8974.0107l-1.084.002Z"/>
</g>
<g id="_Group_" data-name="&lt;Group&gt;">
<g id="_Group_2" data-name="&lt;Group&gt;">
<g id="_Group_3" data-name="&lt;Group&gt;">
<g id="_Group_4" data-name="&lt;Group&gt;">
<path id="_Path_" data-name="&lt;Path&gt;" d="M24.76888,20.30068a4.94881,4.94881,0,0,1,2.35656-4.15206,5.06566,5.06566,0,0,0-3.99116-2.15768c-1.67924-.17626-3.30719,1.00483-4.1629,1.00483-.87227,0-2.18977-.98733-3.6085-.95814a5.31529,5.31529,0,0,0-4.47292,2.72787c-1.934,3.34842-.49141,8.26947,1.3612,10.97608.9269,1.32535,2.01018,2.8058,3.42763,2.7533,1.38706-.05753,1.9051-.88448,3.5794-.88448,1.65876,0,2.14479.88448,3.591.8511,1.48838-.02416,2.42613-1.33124,3.32051-2.66914a10.962,10.962,0,0,0,1.51842-3.09251A4.78205,4.78205,0,0,1,24.76888,20.30068Z" style="fill: #fff"/>
<path id="_Path_2" data-name="&lt;Path&gt;" d="M22.03725,12.21089a4.87248,4.87248,0,0,0,1.11452-3.49062,4.95746,4.95746,0,0,0-3.20758,1.65961,4.63634,4.63634,0,0,0-1.14371,3.36139A4.09905,4.09905,0,0,0,22.03725,12.21089Z" style="fill: #fff"/>
</g>
</g>
<g>
<path d="M46.14895,30.49609V21.35645H46.0884l-3.74316,9.04492H40.91652l-3.75293-9.04492H37.104v9.13965H35.34816v-12.418h2.22949l4.01855,9.80176h.06836l4.01074-9.80176h2.2373v12.418Z" style="fill: #fff"/>
<path d="M49.396,27.92285c0-1.583,1.21289-2.53906,3.36523-2.668l2.47852-.1377v-.68848c0-1.00684-.66309-1.5752-1.791-1.5752a1.73035,1.73035,0,0,0-1.90137,1.27441H49.8091c.05176-1.63574,1.5752-2.79687,3.69141-2.79687,2.16016,0,3.58887,1.17871,3.58887,2.96v6.20508H55.30813V29.00684h-.043a3.23683,3.23683,0,0,1-2.85742,1.64453A2.74447,2.74447,0,0,1,49.396,27.92285Zm5.84375-.81738V26.4082l-2.22949.1377c-1.11035.06934-1.73828.55078-1.73828,1.3252,0,.792.6543,1.30859,1.65234,1.30859A2.17046,2.17046,0,0,0,55.23977,27.10547Z" style="fill: #fff"/>
<path d="M64.89309,24.55762a1.99909,1.99909,0,0,0-2.13379-1.66895c-1.42871,0-2.375,1.19629-2.375,3.08105,0,1.92773.95508,3.08887,2.3916,3.08887a1.94829,1.94829,0,0,0,2.11719-1.626h1.79A3.61835,3.61835,0,0,1,62.7593,30.6084c-2.582,0-4.26855-1.76465-4.26855-4.63867,0-2.81445,1.68652-4.63867,4.251-4.63867a3.63931,3.63931,0,0,1,3.9248,3.22656Z" style="fill: #fff"/>
<path d="M78.7593,27.13965H74.0259l-1.13672,3.35645H70.8843l4.4834-12.418h2.083l4.4834,12.418H79.895Zm-4.24316-1.54883h3.752l-1.84961-5.44727h-.05176Z" style="fill: #fff"/>
<path d="M91.61672,25.96973c0,2.81348-1.50586,4.62109-3.77832,4.62109a3.0693,3.0693,0,0,1-2.84863-1.584h-.043v4.48438H83.0884V21.44238h1.79883v1.50586h.03418a3.21161,3.21161,0,0,1,2.88281-1.60059C90.10207,21.34766,91.61672,23.16406,91.61672,25.96973Zm-1.91016,0c0-1.833-.94727-3.03809-2.39258-3.03809-1.41992,0-2.375,1.23047-2.375,3.03809,0,1.82422.95508,3.0459,2.375,3.0459C88.7593,29.01563,89.70656,27.81934,89.70656,25.96973Z" style="fill: #fff"/>
<path d="M101.58156,25.96973c0,2.81348-1.50586,4.62109-3.77832,4.62109a3.0693,3.0693,0,0,1-2.84863-1.584h-.043v4.48438h-1.8584V21.44238h1.79883v1.50586h.03418a3.21162,3.21162,0,0,1,2.88281-1.60059C100.06691,21.34766,101.58156,23.16406,101.58156,25.96973Zm-1.91016,0c0-1.833-.94727-3.03809-2.39258-3.03809-1.41992,0-2.375,1.23047-2.375,3.03809,0,1.82422.95508,3.0459,2.375,3.0459C98.72414,29.01563,99.67141,27.81934,99.67141,25.96973Z" style="fill: #fff"/>
<path d="M108.1675,27.03613c.1377,1.23145,1.334,2.04,2.96875,2.04,1.56641,0,2.69336-.80859,2.69336-1.91895,0-.96387-.67969-1.541-2.28906-1.93652l-1.60937-.3877c-2.28027-.55078-3.33887-1.61719-3.33887-3.34766,0-2.14258,1.86719-3.61426,4.51855-3.61426,2.624,0,4.42285,1.47168,4.4834,3.61426h-1.876c-.1123-1.23926-1.13672-1.9873-2.63379-1.9873s-2.52149.75684-2.52149,1.8584c0,.87793.65431,1.39453,2.25489,1.79l1.36816.33594c2.54785.60254,3.60645,1.626,3.60645,3.44238,0,2.32324-1.85059,3.77832-4.79395,3.77832-2.75391,0-4.61328-1.4209-4.7334-3.667Z" style="fill: #fff"/>
<path d="M119.80324,19.2998v2.14258h1.72168v1.47168h-1.72168v4.99121c0,.77539.34473,1.13672,1.10156,1.13672a5.80752,5.80752,0,0,0,.61133-.043v1.46289a5.10351,5.10351,0,0,1-1.03223.08594c-1.833,0-2.54785-.68848-2.54785-2.44434V22.91406h-1.31641V21.44238h1.31641V19.2998Z" style="fill: #fff"/>
<path d="M122.521,25.96973c0-2.84863,1.67773-4.63867,4.29395-4.63867,2.625,0,4.29492,1.79,4.29492,4.63867,0,2.85645-1.66113,4.63867-4.29492,4.63867C124.18215,30.6084,122.521,28.82617,122.521,25.96973Zm6.69531,0c0-1.9541-.89551-3.10742-2.40137-3.10742s-2.40137,1.16211-2.40137,3.10742c0,1.96191.89551,3.10645,2.40137,3.10645S129.21633,27.93164,129.21633,25.96973Z" style="fill: #fff"/>
<path d="M132.64309,21.44238h1.77246v1.541h.043a2.1594,2.1594,0,0,1,2.17773-1.63574,2.86616,2.86616,0,0,1,.63672.06934v1.73828a2.598,2.598,0,0,0-.835-.1123,1.87264,1.87264,0,0,0-1.93651,2.083v5.37012h-1.8584Z" style="fill: #fff"/>
<path d="M145.84035,27.83691c-.25,1.64355-1.85059,2.77148-3.89844,2.77148-2.63379,0-4.26855-1.76465-4.26855-4.5957,0-2.83984,1.64355-4.68164,4.19043-4.68164,2.50488,0,4.08008,1.7207,4.08008,4.46582v.63672h-6.39453v.1123a2.358,2.358,0,0,0,2.43555,2.56445,2.04834,2.04834,0,0,0,2.09082-1.27344Zm-6.28223-2.70215h4.52637a2.1773,2.1773,0,0,0-2.2207-2.29785A2.292,2.292,0,0,0,139.55813,25.13477Z" style="fill: #fff"/>
</g>
</g>
</g>
</g>
<g id="_Group_5" data-name="&lt;Group&gt;">
<g>
<path d="M37.82619,8.731a2.63964,2.63964,0,0,1,2.80762,2.96484c0,1.90625-1.03027,3.002-2.80762,3.002H35.67092V8.731Zm-1.22852,5.123h1.125a1.87588,1.87588,0,0,0,1.96777-2.146,1.881,1.881,0,0,0-1.96777-2.13379h-1.125Z" style="fill: #fff"/>
<path d="M41.68068,12.44434a2.13323,2.13323,0,1,1,4.24707,0,2.13358,2.13358,0,1,1-4.24707,0Zm3.333,0c0-.97607-.43848-1.54687-1.208-1.54687-.77246,0-1.207.5708-1.207,1.54688,0,.98389.43457,1.55029,1.207,1.55029C44.57521,13.99463,45.01369,13.42432,45.01369,12.44434Z" style="fill: #fff"/>
<path d="M51.57326,14.69775h-.92187l-.93066-3.31641h-.07031l-.92676,3.31641h-.91309l-1.24121-4.50293h.90137l.80664,3.436h.06641l.92578-3.436h.85254l.92578,3.436h.07031l.80273-3.436h.88867Z" style="fill: #fff"/>
<path d="M53.85354,10.19482H54.709v.71533h.06641a1.348,1.348,0,0,1,1.34375-.80225,1.46456,1.46456,0,0,1,1.55859,1.6748v2.915h-.88867V12.00586c0-.72363-.31445-1.0835-.97168-1.0835a1.03294,1.03294,0,0,0-1.0752,1.14111v2.63428h-.88867Z" style="fill: #fff"/>
<path d="M59.09377,8.437h.88867v6.26074h-.88867Z" style="fill: #fff"/>
<path d="M61.21779,12.44434a2.13323,2.13323,0,1,1,4.24707,0,2.13358,2.13358,0,1,1-4.24707,0Zm3.333,0c0-.97607-.43848-1.54687-1.208-1.54687-.77246,0-1.207.5708-1.207,1.54688,0,.98389.43457,1.55029,1.207,1.55029C64.11232,13.99463,64.5508,13.42432,64.5508,12.44434Z" style="fill: #fff"/>
<path d="M66.40041,13.42432c0-.81055.60352-1.27783,1.6748-1.34424l1.21973-.07031v-.38867c0-.47559-.31445-.74414-.92187-.74414-.49609,0-.83984.18213-.93848.50049h-.86035c.09082-.77344.81836-1.26953,1.83984-1.26953,1.12891,0,1.76563.562,1.76563,1.51318v3.07666h-.85547v-.63281h-.07031a1.515,1.515,0,0,1-1.35254.707A1.36026,1.36026,0,0,1,66.40041,13.42432Zm2.89453-.38477v-.37646l-1.09961.07031c-.62012.0415-.90137.25244-.90137.64941,0,.40527.35156.64111.835.64111A1.0615,1.0615,0,0,0,69.29494,13.03955Z" style="fill: #fff"/>
<path d="M71.34768,12.44434c0-1.42285.73145-2.32422,1.86914-2.32422a1.484,1.484,0,0,1,1.38086.79h.06641V8.437h.88867v6.26074h-.85156v-.71143h-.07031a1.56284,1.56284,0,0,1-1.41406.78564C72.07131,14.772,71.34768,13.87061,71.34768,12.44434Zm.918,0c0,.95508.4502,1.52979,1.20313,1.52979.749,0,1.21191-.583,1.21191-1.52588,0-.93848-.46777-1.52979-1.21191-1.52979C72.72072,10.91846,72.26564,11.49707,72.26564,12.44434Z" style="fill: #fff"/>
<path d="M79.22951,12.44434a2.13346,2.13346,0,1,1,4.24756,0,2.1338,2.1338,0,1,1-4.24756,0Zm3.333,0c0-.97607-.43848-1.54687-1.208-1.54687-.77246,0-1.207.5708-1.207,1.54688,0,.98389.43457,1.55029,1.207,1.55029C82.124,13.99463,82.56252,13.42432,82.56252,12.44434Z" style="fill: #fff"/>
<path d="M84.66945,10.19482h.85547v.71533h.06641a1.348,1.348,0,0,1,1.34375-.80225,1.46456,1.46456,0,0,1,1.55859,1.6748v2.915H87.605V12.00586c0-.72363-.31445-1.0835-.97168-1.0835a1.03294,1.03294,0,0,0-1.0752,1.14111v2.63428h-.88867Z" style="fill: #fff"/>
<path d="M93.51516,9.07373v1.1416h.97559v.74854h-.97559V13.2793c0,.47168.19434.67822.63672.67822a2.96657,2.96657,0,0,0,.33887-.02051v.74023a2.9155,2.9155,0,0,1-.4834.04541c-.98828,0-1.38184-.34766-1.38184-1.21582v-2.543h-.71484v-.74854h.71484V9.07373Z" style="fill: #fff"/>
<path d="M95.70461,8.437h.88086v2.48145h.07031a1.3856,1.3856,0,0,1,1.373-.80664,1.48339,1.48339,0,0,1,1.55078,1.67871v2.90723H98.69v-2.688c0-.71924-.335-1.0835-.96289-1.0835a1.05194,1.05194,0,0,0-1.13379,1.1416v2.62988h-.88867Z" style="fill: #fff"/>
<path d="M104.76125,13.48193a1.828,1.828,0,0,1-1.95117,1.30273A2.04531,2.04531,0,0,1,100.73,12.46045a2.07685,2.07685,0,0,1,2.07617-2.35254c1.25293,0,2.00879.856,2.00879,2.27V12.688h-3.17969v.0498a1.1902,1.1902,0,0,0,1.19922,1.29,1.07934,1.07934,0,0,0,1.07129-.5459Zm-3.126-1.45117h2.27441a1.08647,1.08647,0,0,0-1.1084-1.1665A1.15162,1.15162,0,0,0,101.63527,12.03076Z" style="fill: #fff"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 12 KiB

View file

@ -139,7 +139,9 @@ jobs:
echo "const anonPayReferralCode = '${{ secrets.ANON_PAY_REFERRAL_CODE }}';" >> lib/.secrets.g.dart echo "const anonPayReferralCode = '${{ secrets.ANON_PAY_REFERRAL_CODE }}';" >> lib/.secrets.g.dart
echo "const fiatApiKey = '${{ secrets.FIAT_API_KEY }}';" >> lib/.secrets.g.dart echo "const fiatApiKey = '${{ secrets.FIAT_API_KEY }}';" >> lib/.secrets.g.dart
echo "const payfuraApiKey = '${{ secrets.PAYFURA_API_KEY }}';" >> lib/.secrets.g.dart echo "const payfuraApiKey = '${{ secrets.PAYFURA_API_KEY }}';" >> lib/.secrets.g.dart
echo "const ankrApiKey = '${{ secrets.ANKR_API_KEY }}';" >> lib/.secrets.g.dart
echo "const etherScanApiKey = '${{ secrets.ETHER_SCAN_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart echo "const etherScanApiKey = '${{ secrets.ETHER_SCAN_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart
echo "const moralisApiKey = '${{ secrets.MORALIS_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart
echo "const chatwootWebsiteToken = '${{ secrets.CHATWOOT_WEBSITE_TOKEN }}';" >> lib/.secrets.g.dart echo "const chatwootWebsiteToken = '${{ secrets.CHATWOOT_WEBSITE_TOKEN }}';" >> lib/.secrets.g.dart
echo "const exolixApiKey = '${{ secrets.EXOLIX_API_KEY }}';" >> lib/.secrets.g.dart echo "const exolixApiKey = '${{ secrets.EXOLIX_API_KEY }}';" >> lib/.secrets.g.dart
echo "const robinhoodApplicationId = '${{ secrets.ROBINHOOD_APPLICATION_ID }}';" >> lib/.secrets.g.dart echo "const robinhoodApplicationId = '${{ secrets.ROBINHOOD_APPLICATION_ID }}';" >> lib/.secrets.g.dart

View file

@ -1,15 +1,35 @@
# Cake Wallet for Mobile and Desktop <div align="center">
## Open Source Multi-Currency Wallet <img height="100" src=".github/assets/Logo_CakeWallet.png">
## Links </div>
* Website: https://cakewallet.com ![devices](.github/assets/devices.png)
* App Store (iOS / MacOS): https://cakewallet.com/ios
* Google Play: https://cakewallet.com/gp <div align="center">
* F-Droid: https://fdroid.cakelabs.com
* APK: https://github.com/cake-tech/cake_wallet/releases [<img height="42" src=".github/assets/app-store-badge.svg">](https://apps.apple.com/us/app/cake-wallet/id1334702542?platform=iphone)
* Linux: https://github.com/cake-tech/cake_wallet/releases [<img height="42" src=".github/assets/google-play-badge.png">](https://play.google.com/store/apps/details?id=com.cakewallet.cake_wallet)
[<img height="42" src=".github/assets/f-droid-badge.png">](https://fdroid.cakelabs.com)
[<img height="42" src=".github/assets/mac-store-badge.svg">](https://apps.apple.com/us/app/cake-wallet/id1334702542?platform=mac)
[<img height="42" src=".github/assets/linux-badge.svg">](https://github.com/cake-tech/cake_wallet/releases)
</div>
# Cake Wallet
Cake Wallet is an open source, non-custodial, and private multi-currency crypto wallet for Android, iOS, macOS, and Linux.
Cake Wallet includes support for several cryptocurrencies, including:
* Monero (XMR)
* Bitcoin (BTC)
* Ethereum (ETH)
* Litecoin (LTC)
* Bitcoin Cash (BCH)
* Polygon (MATIC)
* Solana (SOL)
* Nano (XNO)
* Haven (XHV)
## Features ## Features

12
SECURITY.md Normal file
View file

@ -0,0 +1,12 @@
# Security Policy
## Reporting a Vulnerability
If you need to report a vulnerability, please either:
* Open a security advisory: https://github.com/cake-tech/cake_wallet/security/advisories/new
* Send an email to `dev@cakewallet.com` with details on the vulnerability
## Supported Versions
As we don't maintain prevoius versions of the app, only the latest release for each platform is supported and any updates will bump the version number.

View file

@ -3,4 +3,26 @@
useSSL: true useSSL: true
is_default: true is_default: true
- -
uri: node.perish.co:9076 uri: node.nautilus.io
path: /api
useSSL: true
-
uri: app.natrium.io
path: /api
useSSL: true
-
uri: rainstorm.city
path: /api
useSSL: true
-
uri: node.somenano.com
path: /proxy
useSSL: true
-
uri: nanoslo.0x.no
path: /proxy
useSSL: true
-
uri: www.bitrequest.app
port: 8020
useSSL: true

View file

@ -2,7 +2,8 @@ import 'package:cw_bitcoin/bitcoin_transaction_priority.dart';
import 'package:cw_core/output_info.dart'; import 'package:cw_core/output_info.dart';
class BitcoinTransactionCredentials { class BitcoinTransactionCredentials {
BitcoinTransactionCredentials(this.outputs, {required this.priority, this.feeRate}); BitcoinTransactionCredentials(this.outputs,
{required this.priority, this.feeRate});
final List<OutputInfo> outputs; final List<OutputInfo> outputs;
final BitcoinTransactionPriority? priority; final BitcoinTransactionPriority? priority;

View file

@ -4,13 +4,15 @@ class BitcoinTransactionPriority extends TransactionPriority {
const BitcoinTransactionPriority({required String title, required int raw}) const BitcoinTransactionPriority({required String title, required int raw})
: super(title: title, raw: raw); : super(title: title, raw: raw);
static const List<BitcoinTransactionPriority> all = [fast, medium, slow]; static const List<BitcoinTransactionPriority> all = [fast, medium, slow, custom];
static const BitcoinTransactionPriority slow = static const BitcoinTransactionPriority slow =
BitcoinTransactionPriority(title: 'Slow', raw: 0); BitcoinTransactionPriority(title: 'Slow', raw: 0);
static const BitcoinTransactionPriority medium = static const BitcoinTransactionPriority medium =
BitcoinTransactionPriority(title: 'Medium', raw: 1); BitcoinTransactionPriority(title: 'Medium', raw: 1);
static const BitcoinTransactionPriority fast = static const BitcoinTransactionPriority fast =
BitcoinTransactionPriority(title: 'Fast', raw: 2); BitcoinTransactionPriority(title: 'Fast', raw: 2);
static const BitcoinTransactionPriority custom =
BitcoinTransactionPriority(title: 'Custom', raw: 3);
static BitcoinTransactionPriority deserialize({required int raw}) { static BitcoinTransactionPriority deserialize({required int raw}) {
switch (raw) { switch (raw) {
@ -20,6 +22,8 @@ class BitcoinTransactionPriority extends TransactionPriority {
return medium; return medium;
case 2: case 2:
return fast; return fast;
case 3:
return custom;
default: default:
throw Exception('Unexpected token: $raw for BitcoinTransactionPriority deserialize'); throw Exception('Unexpected token: $raw for BitcoinTransactionPriority deserialize');
} }
@ -39,7 +43,10 @@ class BitcoinTransactionPriority extends TransactionPriority {
label = 'Medium'; // S.current.transaction_priority_medium; label = 'Medium'; // S.current.transaction_priority_medium;
break; break;
case BitcoinTransactionPriority.fast: case BitcoinTransactionPriority.fast:
label = 'Fast'; // S.current.transaction_priority_fast; label = 'Fast';
break; // S.current.transaction_priority_fast;
case BitcoinTransactionPriority.custom:
label = 'Custom';
break; break;
default: default:
break; break;
@ -48,7 +55,10 @@ class BitcoinTransactionPriority extends TransactionPriority {
return label; return label;
} }
String labelWithRate(int rate) => '${toString()} ($rate ${units}/byte)'; String labelWithRate(int rate, int? customRate) {
final rateValue = this == custom ? customRate ??= 0 : rate;
return '${toString()} ($rateValue ${units}/byte)';
}
} }
class LitecoinTransactionPriority extends BitcoinTransactionPriority { class LitecoinTransactionPriority extends BitcoinTransactionPriority {

View file

@ -11,12 +11,11 @@ import 'package:cw_core/wallet_type.dart';
class ElectrumTransactionBundle { class ElectrumTransactionBundle {
ElectrumTransactionBundle(this.originalTransaction, ElectrumTransactionBundle(this.originalTransaction,
{required this.ins, required this.confirmations, this.time, required this.height}); {required this.ins, required this.confirmations, this.time});
final BtcTransaction originalTransaction; final BtcTransaction originalTransaction;
final List<BtcTransaction> ins; final List<BtcTransaction> ins;
final int? time; final int? time;
final int confirmations; final int confirmations;
final int height;
} }
class ElectrumTransactionInfo extends TransactionInfo { class ElectrumTransactionInfo extends TransactionInfo {
@ -25,6 +24,8 @@ class ElectrumTransactionInfo extends TransactionInfo {
required int height, required int height,
required int amount, required int amount,
int? fee, int? fee,
List<String>? inputAddresses,
List<String>? outputAddresses,
required TransactionDirection direction, required TransactionDirection direction,
required bool isPending, required bool isPending,
required DateTime date, required DateTime date,
@ -32,6 +33,8 @@ class ElectrumTransactionInfo extends TransactionInfo {
this.id = id; this.id = id;
this.height = height; this.height = height;
this.amount = amount; this.amount = amount;
this.inputAddresses = inputAddresses;
this.outputAddresses = outputAddresses;
this.fee = fee; this.fee = fee;
this.direction = direction; this.direction = direction;
this.date = date; this.date = date;
@ -100,6 +103,8 @@ class ElectrumTransactionInfo extends TransactionInfo {
var amount = 0; var amount = 0;
var inputAmount = 0; var inputAmount = 0;
var totalOutAmount = 0; var totalOutAmount = 0;
List<String> inputAddresses = [];
List<String> outputAddresses = [];
for (var i = 0; i < bundle.originalTransaction.inputs.length; i++) { for (var i = 0; i < bundle.originalTransaction.inputs.length; i++) {
final input = bundle.originalTransaction.inputs[i]; final input = bundle.originalTransaction.inputs[i];
@ -108,6 +113,7 @@ class ElectrumTransactionInfo extends TransactionInfo {
inputAmount += outTransaction.amount.toInt(); inputAmount += outTransaction.amount.toInt();
if (addresses.contains(addressFromOutputScript(outTransaction.scriptPubKey, network))) { if (addresses.contains(addressFromOutputScript(outTransaction.scriptPubKey, network))) {
direction = TransactionDirection.outgoing; direction = TransactionDirection.outgoing;
inputAddresses.add(addressFromOutputScript(outTransaction.scriptPubKey, network));
} }
} }
@ -115,6 +121,7 @@ class ElectrumTransactionInfo extends TransactionInfo {
for (final out in bundle.originalTransaction.outputs) { for (final out in bundle.originalTransaction.outputs) {
totalOutAmount += out.amount.toInt(); totalOutAmount += out.amount.toInt();
final addressExists = addresses.contains(addressFromOutputScript(out.scriptPubKey, network)); final addressExists = addresses.contains(addressFromOutputScript(out.scriptPubKey, network));
outputAddresses.add(addressFromOutputScript(out.scriptPubKey, network));
if (addressExists) { if (addressExists) {
receivedAmounts.add(out.amount.toInt()); receivedAmounts.add(out.amount.toInt());
@ -137,6 +144,8 @@ class ElectrumTransactionInfo extends TransactionInfo {
id: bundle.originalTransaction.txId(), id: bundle.originalTransaction.txId(),
height: height, height: height,
isPending: bundle.confirmations == 0, isPending: bundle.confirmations == 0,
inputAddresses: inputAddresses,
outputAddresses: outputAddresses,
fee: fee, fee: fee,
direction: direction, direction: direction,
amount: amount, amount: amount,
@ -187,6 +196,8 @@ class ElectrumTransactionInfo extends TransactionInfo {
direction: parseTransactionDirectionFromInt(data['direction'] as int), direction: parseTransactionDirectionFromInt(data['direction'] as int),
date: DateTime.fromMillisecondsSinceEpoch(data['date'] as int), date: DateTime.fromMillisecondsSinceEpoch(data['date'] as int),
isPending: data['isPending'] as bool, isPending: data['isPending'] as bool,
inputAddresses: data['inputAddresses'] as List<String>,
outputAddresses: data['outputAddresses'] as List<String>,
confirmations: data['confirmations'] as int); confirmations: data['confirmations'] as int);
} }
@ -218,6 +229,8 @@ class ElectrumTransactionInfo extends TransactionInfo {
direction: direction, direction: direction,
date: date, date: date,
isPending: isPending, isPending: isPending,
inputAddresses: inputAddresses,
outputAddresses: outputAddresses,
confirmations: info.confirmations); confirmations: info.confirmations);
} }
@ -231,6 +244,8 @@ class ElectrumTransactionInfo extends TransactionInfo {
m['isPending'] = isPending; m['isPending'] = isPending;
m['confirmations'] = confirmations; m['confirmations'] = confirmations;
m['fee'] = fee; m['fee'] = fee;
m['inputAddresses'] = inputAddresses;
m['outputAddresses'] = outputAddresses;
return m; return m;
} }
} }

View file

@ -7,6 +7,7 @@ import 'package:bitcoin_base/bitcoin_base.dart';
import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin; import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
import 'package:bitcoin_base/bitcoin_base.dart' as bitcoin_base; import 'package:bitcoin_base/bitcoin_base.dart' as bitcoin_base;
import 'package:collection/collection.dart'; import 'package:collection/collection.dart';
import 'package:cw_bitcoin/address_from_output.dart';
import 'package:cw_bitcoin/bitcoin_address_record.dart'; import 'package:cw_bitcoin/bitcoin_address_record.dart';
import 'package:cw_bitcoin/bitcoin_amount_format.dart'; import 'package:cw_bitcoin/bitcoin_amount_format.dart';
import 'package:cw_bitcoin/bitcoin_transaction_credentials.dart'; import 'package:cw_bitcoin/bitcoin_transaction_credentials.dart';
@ -188,11 +189,9 @@ abstract class ElectrumWalletBase
} }
} }
int _getDustAmount() { int get _dustAmount => 546;
return 546;
}
bool _isBelowDust(int amount) => amount <= _getDustAmount() && network != BitcoinNetwork.testnet; bool _isBelowDust(int amount) => amount <= _dustAmount && network != BitcoinNetwork.testnet;
Future<EstimatedTxResult> estimateSendAllTx( Future<EstimatedTxResult> estimateSendAllTx(
List<BitcoinOutput> outputs, List<BitcoinOutput> outputs,
@ -418,7 +417,7 @@ abstract class ElectrumWalletBase
} }
// Estimate to user how much is needed to send to cover the fee // Estimate to user how much is needed to send to cover the fee
final maxAmountWithReturningChange = allInputsAmount - _getDustAmount() - fee - 1; final maxAmountWithReturningChange = allInputsAmount - _dustAmount - fee - 1;
throw BitcoinTransactionNoDustOnChangeException( throw BitcoinTransactionNoDustOnChangeException(
bitcoinAmountToString(amount: maxAmountWithReturningChange), bitcoinAmountToString(amount: maxAmountWithReturningChange),
bitcoinAmountToString(amount: estimatedSendAll.amount), bitcoinAmountToString(amount: estimatedSendAll.amount),
@ -532,6 +531,7 @@ abstract class ElectrumWalletBase
network: network, network: network,
memo: estimatedTx.memo, memo: estimatedTx.memo,
outputOrdering: BitcoinOrdering.none, outputOrdering: BitcoinOrdering.none,
enableRBF: true,
); );
} else { } else {
txb = BitcoinTransactionBuilder( txb = BitcoinTransactionBuilder(
@ -541,6 +541,7 @@ abstract class ElectrumWalletBase
network: network, network: network,
memo: estimatedTx.memo, memo: estimatedTx.memo,
outputOrdering: BitcoinOrdering.none, outputOrdering: BitcoinOrdering.none,
enableRBF: true,
); );
} }
@ -794,8 +795,180 @@ abstract class ElectrumWalletBase
} }
} }
Future<ElectrumTransactionBundle> getTransactionExpanded( Future<bool> canReplaceByFee(String hash) async {
{required String hash, required int height}) async { final verboseTransaction = await electrumClient.getTransactionRaw(hash: hash);
final confirmations = verboseTransaction['confirmations'] as int? ?? 0;
final transactionHex = verboseTransaction['hex'] as String?;
if (confirmations > 0) return false;
if (transactionHex == null) {
return false;
}
final original = bitcoin.Transaction.fromHex(transactionHex);
return original.ins
.any((element) => element.sequence != null && element.sequence! < 4294967293);
}
Future<bool> isChangeSufficientForFee(String txId, int newFee) async {
final bundle = await getTransactionExpanded(hash: txId);
final outputs = bundle.originalTransaction.outputs;
final changeAddresses = walletAddresses.allAddresses.where((element) => element.isHidden);
// look for a change address in the outputs
final changeOutput = outputs.firstWhereOrNull((output) => changeAddresses.any(
(element) => element.address == addressFromOutputScript(output.scriptPubKey, network)));
var allInputsAmount = 0;
for (int i = 0; i < bundle.originalTransaction.inputs.length; i++) {
final input = bundle.originalTransaction.inputs[i];
final inputTransaction = bundle.ins[i];
final vout = input.txIndex;
final outTransaction = inputTransaction.outputs[vout];
allInputsAmount += outTransaction.amount.toInt();
}
int totalOutAmount = bundle.originalTransaction.outputs
.fold<int>(0, (previousValue, element) => previousValue + element.amount.toInt());
var currentFee = allInputsAmount - totalOutAmount;
int remainingFee = (newFee - currentFee > 0) ? newFee - currentFee : newFee;
return changeOutput != null && changeOutput.amount.toInt() - remainingFee >= 0;
}
Future<PendingBitcoinTransaction> replaceByFee(String hash, int newFee) async {
try {
final bundle = await getTransactionExpanded(hash: hash);
final utxos = <UtxoWithAddress>[];
List<ECPrivate> privateKeys = [];
var allInputsAmount = 0;
// Add inputs
for (var i = 0; i < bundle.originalTransaction.inputs.length; i++) {
final input = bundle.originalTransaction.inputs[i];
final inputTransaction = bundle.ins[i];
final vout = input.txIndex;
final outTransaction = inputTransaction.outputs[vout];
final address = addressFromOutputScript(outTransaction.scriptPubKey, network);
allInputsAmount += outTransaction.amount.toInt();
final addressRecord =
walletAddresses.allAddresses.firstWhere((element) => element.address == address);
final btcAddress = addressTypeFromStr(addressRecord.address, network);
final privkey = generateECPrivate(
hd: addressRecord.isHidden ? walletAddresses.sideHd : walletAddresses.mainHd,
index: addressRecord.index,
network: network);
privateKeys.add(privkey);
utxos.add(
UtxoWithAddress(
utxo: BitcoinUtxo(
txHash: input.txId,
value: outTransaction.amount,
vout: vout,
scriptType: _getScriptType(btcAddress),
),
ownerDetails:
UtxoAddressDetails(publicKey: privkey.getPublic().toHex(), address: btcAddress),
),
);
}
int totalOutAmount = bundle.originalTransaction.outputs
.fold<int>(0, (previousValue, element) => previousValue + element.amount.toInt());
var currentFee = allInputsAmount - totalOutAmount;
int remainingFee = newFee - currentFee;
final outputs = <BitcoinOutput>[];
// Add outputs and deduct the fees from it
for (int i = bundle.originalTransaction.outputs.length - 1; i >= 0; i--) {
final out = bundle.originalTransaction.outputs[i];
final address = addressFromOutputScript(out.scriptPubKey, network);
final btcAddress = addressTypeFromStr(address, network);
int newAmount;
if (out.amount.toInt() >= remainingFee) {
newAmount = out.amount.toInt() - remainingFee;
remainingFee = 0;
// if new amount of output is less than dust amount, then don't add this output as well
if (newAmount <= _dustAmount) {
continue;
}
} else {
remainingFee -= out.amount.toInt();
continue;
}
outputs.add(BitcoinOutput(address: btcAddress, value: BigInt.from(newAmount)));
}
final changeAddresses = walletAddresses.allAddresses.where((element) => element.isHidden);
// look for a change address in the outputs
final changeOutput = outputs.firstWhereOrNull((output) =>
changeAddresses.any((element) => element.address == output.address.toAddress(network)));
// deduct the change amount from the output amount
if (changeOutput != null) {
totalOutAmount -= changeOutput.value.toInt();
}
final txb = BitcoinTransactionBuilder(
utxos: utxos,
outputs: outputs,
fee: BigInt.from(newFee),
network: network,
enableRBF: true,
);
final transaction = txb.buildTransaction((txDigest, utxo, publicKey, sighash) {
final key =
privateKeys.firstWhereOrNull((element) => element.getPublic().toHex() == publicKey);
if (key == null) {
throw Exception("Cannot find private key");
}
if (utxo.utxo.isP2tr()) {
return key.signTapRoot(txDigest, sighash: sighash);
} else {
return key.signInput(txDigest, sigHash: sighash);
}
});
return PendingBitcoinTransaction(
transaction,
type,
electrumClient: electrumClient,
amount: totalOutAmount,
fee: newFee,
network: network,
hasChange: changeOutput != null,
feeRate: newFee.toString(),
)..addListener((transaction) async {
transactionHistory.addOne(transaction);
await updateBalance();
});
} catch (e) {
throw e;
}
}
Future<ElectrumTransactionBundle> getTransactionExpanded({required String hash}) async {
String transactionHex; String transactionHex;
int? time; int? time;
int confirmations = 0; int confirmations = 0;
@ -826,8 +999,12 @@ abstract class ElectrumWalletBase
ins.add(tx); ins.add(tx);
} }
return ElectrumTransactionBundle(original, return ElectrumTransactionBundle(
ins: ins, time: time, confirmations: confirmations, height: height); original,
ins: ins,
time: time,
confirmations: confirmations,
);
} }
Future<ElectrumTransactionInfo?> fetchTransactionInfo( Future<ElectrumTransactionInfo?> fetchTransactionInfo(
@ -837,7 +1014,7 @@ abstract class ElectrumWalletBase
bool? retryOnFailure}) async { bool? retryOnFailure}) async {
try { try {
return ElectrumTransactionInfo.fromElectrumBundle( return ElectrumTransactionInfo.fromElectrumBundle(
await getTransactionExpanded(hash: hash, height: height), walletInfo.type, network, await getTransactionExpanded(hash: hash), walletInfo.type, network,
addresses: myAddresses, height: height); addresses: myAddresses, height: height);
} catch (e) { } catch (e) {
if (e is FormatException && retryOnFailure == true) { if (e is FormatException && retryOnFailure == true) {

View file

@ -241,6 +241,8 @@ abstract class ElectrumWalletAddressesBase extends WalletAddresses with Store {
final index = _addresses.indexOf(addressRecord); final index = _addresses.indexOf(addressRecord);
_addresses.remove(addressRecord); _addresses.remove(addressRecord);
_addresses.insert(index, addressRecord); _addresses.insert(index, addressRecord);
updateAddressesByMatch();
} }
@action @action

View file

@ -17,7 +17,7 @@ class PendingBitcoinTransaction with PendingTransaction {
required this.feeRate, required this.feeRate,
this.network, this.network,
required this.hasChange, required this.hasChange,
required this.isSendAll, this.isSendAll = false,
this.hasTaprootInputs = false, this.hasTaprootInputs = false,
}) : _listeners = <void Function(ElectrumTransactionInfo transaction)>[]; }) : _listeners = <void Function(ElectrumTransactionInfo transaction)>[];

View file

@ -70,8 +70,8 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
path: "." path: "."
ref: master ref: Add-Support-For-OP-Return-data
resolved-ref: ea65073efbaf395a5557e8cd7bd72f195cd7eb11 resolved-ref: "57b78afb85bd2c30d3cdb9f7884f3878a62be442"
url: "https://github.com/cake-tech/bitbox-flutter.git" url: "https://github.com/cake-tech/bitbox-flutter.git"
source: git source: git
version: "1.0.1" version: "1.0.1"

View file

@ -26,7 +26,7 @@ dependencies:
bitbox: bitbox:
git: git:
url: https://github.com/cake-tech/bitbox-flutter.git url: https://github.com/cake-tech/bitbox-flutter.git
ref: master ref: Add-Support-For-OP-Return-data
rxdart: ^0.27.5 rxdart: ^0.27.5
unorm_dart: ^0.2.0 unorm_dart: ^0.2.0
cryptography: ^2.0.5 cryptography: ^2.0.5

View file

@ -28,7 +28,7 @@ dependencies:
bitbox: bitbox:
git: git:
url: https://github.com/cake-tech/bitbox-flutter.git url: https://github.com/cake-tech/bitbox-flutter.git
ref: master ref: Add-Support-For-OP-Return-data
bitcoin_base: bitcoin_base:
git: git:
url: https://github.com/cake-tech/bitcoin_base.git url: https://github.com/cake-tech/bitcoin_base.git

31
cw_core/lib/n2_node.dart Normal file
View file

@ -0,0 +1,31 @@
class N2Node {
N2Node({
this.weight,
this.uptime,
this.score,
this.account,
this.alias,
});
String? uptime;
double? weight;
int? score;
String? account;
String? alias;
factory N2Node.fromJson(Map<String, dynamic> json) => N2Node(
weight: double.tryParse((json['weight'] as num?).toString()),
uptime: json['uptime'] as String?,
score: json['score'] as int?,
account: json['rep_address'] as String?,
alias: json['alias'] as String?,
);
Map<String, dynamic> toJson() => <String, dynamic>{
'uptime': uptime,
'weight': weight,
'score': score,
'rep_address': account,
'alias': alias,
};
}

View file

@ -21,6 +21,7 @@ class Node extends HiveObject with Keyable {
this.trusted = false, this.trusted = false,
this.socksProxyAddress, this.socksProxyAddress,
String? uri, String? uri,
String? path,
WalletType? type, WalletType? type,
}) { }) {
if (uri != null) { if (uri != null) {
@ -29,10 +30,14 @@ class Node extends HiveObject with Keyable {
if (type != null) { if (type != null) {
this.type = type; this.type = type;
} }
if (path != null) {
this.path = path;
}
} }
Node.fromMap(Map<String, Object?> map) Node.fromMap(Map<String, Object?> map)
: uriRaw = map['uri'] as String? ?? '', : uriRaw = map['uri'] as String? ?? '',
path = map['path'] as String? ?? '',
login = map['login'] as String?, login = map['login'] as String?,
password = map['password'] as String?, password = map['password'] as String?,
useSSL = map['useSSL'] as bool?, useSSL = map['useSSL'] as bool?,
@ -63,6 +68,9 @@ class Node extends HiveObject with Keyable {
@HiveField(6) @HiveField(6)
String? socksProxyAddress; String? socksProxyAddress;
@HiveField(7, defaultValue: '')
String? path;
bool get isSSL => useSSL ?? false; bool get isSSL => useSSL ?? false;
bool get useSocksProxy => socksProxyAddress == null ? false : socksProxyAddress!.isNotEmpty; bool get useSocksProxy => socksProxyAddress == null ? false : socksProxyAddress!.isNotEmpty;
@ -79,9 +87,9 @@ class Node extends HiveObject with Keyable {
case WalletType.nano: case WalletType.nano:
case WalletType.banano: case WalletType.banano:
if (isSSL) { if (isSSL) {
return Uri.https(uriRaw, ''); return Uri.https(uriRaw, path ?? '');
} else { } else {
return Uri.http(uriRaw, ''); return Uri.http(uriRaw, path ?? '');
} }
case WalletType.ethereum: case WalletType.ethereum:
case WalletType.polygon: case WalletType.polygon:
@ -103,7 +111,8 @@ class Node extends HiveObject with Keyable {
other.typeRaw == typeRaw && other.typeRaw == typeRaw &&
other.useSSL == useSSL && other.useSSL == useSSL &&
other.trusted == trusted && other.trusted == trusted &&
other.socksProxyAddress == socksProxyAddress); other.socksProxyAddress == socksProxyAddress &&
other.path == path);
@override @override
int get hashCode => int get hashCode =>
@ -113,7 +122,8 @@ class Node extends HiveObject with Keyable {
typeRaw.hashCode ^ typeRaw.hashCode ^
useSSL.hashCode ^ useSSL.hashCode ^
trusted.hashCode ^ trusted.hashCode ^
socksProxyAddress.hashCode; socksProxyAddress.hashCode ^
path.hashCode;
@override @override
dynamic get keyIndex { dynamic get keyIndex {

View file

@ -16,6 +16,8 @@ abstract class TransactionInfo extends Object with Keyable {
void changeFiatAmount(String amount); void changeFiatAmount(String amount);
String? to; String? to;
String? from; String? from;
List<String>? inputAddresses;
List<String>? outputAddresses;
@override @override
dynamic get keyIndex => id; dynamic get keyIndex => id;

View file

@ -41,5 +41,6 @@ abstract class WalletAddresses {
} }
} }
bool containsAddress(String address) => allAddressesMap.containsKey(address); bool containsAddress(String address) =>
addressesMap.containsKey(address) || allAddressesMap.containsKey(address);
} }

View file

@ -67,6 +67,7 @@ abstract class WalletBase<BalanceType extends Balance, HistoryType extends Trans
int calculateEstimatedFee(TransactionPriority priority, int? amount); int calculateEstimatedFee(TransactionPriority priority, int? amount);
// void fetchTransactionsAsync( // void fetchTransactionsAsync(
// void Function(TransactionType transaction) onTransactionLoaded, // void Function(TransactionType transaction) onTransactionLoaded,
// {void Function() onFinished}); // {void Function() onFinished});

View file

@ -1,4 +1,5 @@
import 'dart:async'; import 'dart:async';
import 'dart:convert';
import 'dart:developer'; import 'dart:developer';
import 'package:cw_core/node.dart'; import 'package:cw_core/node.dart';
@ -9,6 +10,7 @@ import 'package:cw_evm/evm_erc20_balance.dart';
import 'package:cw_evm/evm_chain_transaction_model.dart'; import 'package:cw_evm/evm_chain_transaction_model.dart';
import 'package:cw_evm/pending_evm_chain_transaction.dart'; import 'package:cw_evm/pending_evm_chain_transaction.dart';
import 'package:cw_evm/evm_chain_transaction_priority.dart'; import 'package:cw_evm/evm_chain_transaction_priority.dart';
import 'package:cw_evm/.secrets.g.dart' as secrets;
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:http/http.dart'; import 'package:http/http.dart';
@ -211,26 +213,61 @@ abstract class EVMChainClient {
return EVMChainERC20Balance(balance, exponent: exponent); return EVMChainERC20Balance(balance, exponent: exponent);
} }
Future<Erc20Token?> getErc20Token(String contractAddress) async { Future<Erc20Token?> getErc20Token(String contractAddress, String chainName) async {
try { try {
final erc20 = ERC20(address: EthereumAddress.fromHex(contractAddress), client: _client!); final uri = Uri.https(
final name = await erc20.name(); 'deep-index.moralis.io',
final symbol = await erc20.symbol(); '/api/v2.2/erc20/metadata',
final decimal = await erc20.decimals(); {
"chain": chainName,
"addresses": contractAddress,
},
);
final response = await httpClient.get(
uri,
headers: {
"Accept": "application/json",
"X-API-Key": secrets.moralisApiKey,
},
);
final decodedResponse = jsonDecode(response.body)[0] as Map<String, dynamic>;
final name = decodedResponse['name'] ?? '';
final symbol = decodedResponse['symbol'] ?? '';
final decimal = decodedResponse['decimals'] ?? '0';
final iconPath = decodedResponse['logo'] ?? '';
return Erc20Token( return Erc20Token(
name: name, name: name,
symbol: symbol, symbol: symbol,
contractAddress: contractAddress, contractAddress: contractAddress,
decimal: decimal.toInt(), decimal: int.tryParse(decimal) ?? 0,
iconPath: iconPath,
); );
} catch (e) { } catch (e) {
try {
final erc20 = ERC20(address: EthereumAddress.fromHex(contractAddress), client: _client!);
final name = await erc20.name();
final symbol = await erc20.symbol();
final decimal = await erc20.decimals();
return Erc20Token(
name: name,
symbol: symbol,
contractAddress: contractAddress,
decimal: decimal.toInt(),
);
} catch (_) {}
return null; return null;
} }
} }
Uint8List hexToBytes(String hexString) { Uint8List hexToBytes(String hexString) {
return Uint8List.fromList(hex.HEX.decode(hexString.startsWith('0x') ? hexString.substring(2) : hexString)); return Uint8List.fromList(
hex.HEX.decode(hexString.startsWith('0x') ? hexString.substring(2) : hexString));
} }
void stop() { void stop() {

View file

@ -439,11 +439,16 @@ abstract class EVMChainWalletBase
Future<void> addErc20Token(Erc20Token token) async { Future<void> addErc20Token(Erc20Token token) async {
String? iconPath; String? iconPath;
try {
iconPath = CryptoCurrency.all if (token.iconPath == null || token.iconPath!.isEmpty) {
.firstWhere((element) => element.title.toUpperCase() == token.symbol.toUpperCase()) try {
.iconPath; iconPath = CryptoCurrency.all
} catch (_) {} .firstWhere((element) => element.title.toUpperCase() == token.symbol.toUpperCase())
.iconPath;
} catch (_) {}
} else {
iconPath = token.iconPath;
}
final newToken = createNewErc20TokenObject(token, iconPath); final newToken = createNewErc20TokenObject(token, iconPath);
@ -466,8 +471,8 @@ abstract class EVMChainWalletBase
_updateBalance(); _updateBalance();
} }
Future<Erc20Token?> getErc20Token(String contractAddress) async => Future<Erc20Token?> getErc20Token(String contractAddress, String chainName) async =>
await _client.getErc20Token(contractAddress); await _client.getErc20Token(contractAddress, chainName);
void _onNewTransaction() { void _onNewTransaction() {
_updateBalance(); _updateBalance();

View file

@ -2,6 +2,7 @@ import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'package:cw_core/nano_account_info_response.dart'; import 'package:cw_core/nano_account_info_response.dart';
import 'package:cw_core/n2_node.dart';
import 'package:cw_nano/nano_balance.dart'; import 'package:cw_nano/nano_balance.dart';
import 'package:cw_nano/nano_transaction_model.dart'; import 'package:cw_nano/nano_transaction_model.dart';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
@ -16,6 +17,8 @@ class NanoClient {
"nano-app": "cake-wallet" "nano-app": "cake-wallet"
}; };
static const String N2_REPS_ENDPOINT = "https://rpc.nano.to";
NanoClient() { NanoClient() {
SharedPreferences.getInstance().then((value) => prefs = value); SharedPreferences.getInstance().then((value) => prefs = value);
} }
@ -418,7 +421,7 @@ class NanoClient {
body: jsonEncode({ body: jsonEncode({
"action": "account_history", "action": "account_history",
"account": address, "account": address,
"count": "250", // TODO: pick a number "count": "100",
// "raw": true, // "raw": true,
})); }));
final data = await jsonDecode(response.body); final data = await jsonDecode(response.body);
@ -434,4 +437,37 @@ class NanoClient {
return []; return [];
} }
} }
Future<List<N2Node>> getN2Reps() async {
final response = await http.post(
Uri.parse(N2_REPS_ENDPOINT),
headers: CAKE_HEADERS,
body: jsonEncode({"action": "reps"}),
);
try {
final List<N2Node> nodes = (json.decode(response.body) as List<dynamic>)
.map((dynamic e) => N2Node.fromJson(e as Map<String, dynamic>))
.toList();
return nodes;
} catch (error) {
return [];
}
}
Future<int> getRepScore(String rep) async {
final response = await http.post(
Uri.parse(N2_REPS_ENDPOINT),
headers: CAKE_HEADERS,
body: jsonEncode({
"action": "rep_info",
"account": rep,
}),
);
try {
final N2Node node = N2Node.fromJson(json.decode(response.body) as Map<String, dynamic>);
return node.score ?? 100;
} catch (error) {
return 100;
}
}
} }

View file

@ -13,6 +13,7 @@ import 'package:cw_core/transaction_priority.dart';
import 'package:cw_core/wallet_info.dart'; import 'package:cw_core/wallet_info.dart';
import 'package:cw_nano/file.dart'; import 'package:cw_nano/file.dart';
import 'package:cw_core/nano_account.dart'; import 'package:cw_core/nano_account.dart';
import 'package:cw_core/n2_node.dart';
import 'package:cw_nano/nano_balance.dart'; import 'package:cw_nano/nano_balance.dart';
import 'package:cw_nano/nano_client.dart'; import 'package:cw_nano/nano_client.dart';
import 'package:cw_nano/nano_transaction_credentials.dart'; import 'package:cw_nano/nano_transaction_credentials.dart';
@ -65,9 +66,11 @@ abstract class NanoWalletBase
String? _privateKey; String? _privateKey;
String? _publicAddress; String? _publicAddress;
String? _hexSeed; String? _hexSeed;
Timer? _receiveTimer;
String? _representativeAddress; String? _representativeAddress;
Timer? _receiveTimer; int repScore = 100;
bool get isRepOk => repScore >= 90;
late final NanoClient _client; late final NanoClient _client;
bool _isTransactionUpdating; bool _isTransactionUpdating;
@ -375,7 +378,7 @@ abstract class NanoWalletBase
final data = json.decode(jsonSource) as Map; final data = json.decode(jsonSource) as Map;
final mnemonic = data['mnemonic'] as String; final mnemonic = data['mnemonic'] as String;
final balance = NanoBalance.fromRawString( final balance = NanoBalance.fromRawString(
currentBalance: data['currentBalance'] as String? ?? "0", currentBalance: data['currentBalance'] as String? ?? "0",
receivableBalance: data['receivableBalance'] as String? ?? "0", receivableBalance: data['receivableBalance'] as String? ?? "0",
@ -429,6 +432,8 @@ abstract class NanoWalletBase
_representativeAddress = await _client.getRepFromPrefs(); _representativeAddress = await _client.getRepFromPrefs();
throw Exception("Failed to get representative address $e"); throw Exception("Failed to get representative address $e");
} }
repScore = await _client.getRepScore(_representativeAddress!);
} }
Future<void> regenerateAddress() async { Future<void> regenerateAddress() async {
@ -465,6 +470,10 @@ abstract class NanoWalletBase
} }
} }
Future<List<N2Node>> getN2Reps() async {
return _client.getN2Reps();
}
Future<void>? updateBalance() async => await _updateBalance(); Future<void>? updateBalance() async => await _updateBalance();
@override @override

View file

@ -533,4 +533,21 @@ class SolanaWalletClient {
throw Exception(e); throw Exception(e);
} }
} }
Future<String?> getIconImageFromTokenUri(String uri) async {
try {
final response = await httpClient.get(Uri.parse(uri));
final jsonResponse = json.decode(response.body) as Map<String, dynamic>;
if (response.statusCode >= 200 && response.statusCode < 300) {
return jsonResponse['image'];
} else {
return null;
}
} catch (e) {
print('Error occurred while fetching token image: \n${e.toString()}');
return null;
}
}
} }

View file

@ -464,11 +464,17 @@ abstract class SolanaWalletBase
return null; return null;
} }
String? iconPath;
try {
iconPath = await _client.getIconImageFromTokenUri(token.uri);
} catch (_) {}
return SPLToken.fromMetadata( return SPLToken.fromMetadata(
name: token.name, name: token.name,
mint: token.mint, mint: token.mint,
symbol: token.symbol, symbol: token.symbol,
mintAddress: mintAddress, mintAddress: mintAddress,
iconPath: iconPath,
); );
} catch (e) { } catch (e) {
return null; return null;

View file

@ -55,6 +55,7 @@ class SPLToken extends CryptoCurrency with HiveObjectMixin {
required String mint, required String mint,
required String symbol, required String symbol,
required String mintAddress, required String mintAddress,
String? iconPath
}) { }) {
return SPLToken( return SPLToken(
name: name, name: name,
@ -62,7 +63,7 @@ class SPLToken extends CryptoCurrency with HiveObjectMixin {
mintAddress: mintAddress, mintAddress: mintAddress,
decimal: 0, decimal: 0,
mint: mint, mint: mint,
iconPath: '', iconPath: iconPath,
); );
} }

View file

@ -74,22 +74,26 @@ class CWBitcoin extends Bitcoin {
@override @override
Object createBitcoinTransactionCredentials(List<Output> outputs, Object createBitcoinTransactionCredentials(List<Output> outputs,
{required TransactionPriority priority, int? feeRate}) => {required TransactionPriority priority, int? feeRate}) {
BitcoinTransactionCredentials( final bitcoinFeeRate =
outputs priority == BitcoinTransactionPriority.custom && feeRate != null ? feeRate : null;
.map((out) => OutputInfo( return BitcoinTransactionCredentials(
fiatAmount: out.fiatAmount, outputs
cryptoAmount: out.cryptoAmount, .map((out) => OutputInfo(
address: out.address, fiatAmount: out.fiatAmount,
note: out.note, cryptoAmount: out.cryptoAmount,
sendAll: out.sendAll, address: out.address,
extractedAddress: out.extractedAddress, note: out.note,
isParsedAddress: out.isParsedAddress, sendAll: out.sendAll,
formattedCryptoAmount: out.formattedCryptoAmount, extractedAddress: out.extractedAddress,
memo: out.memo)) isParsedAddress: out.isParsedAddress,
.toList(), formattedCryptoAmount: out.formattedCryptoAmount,
priority: priority as BitcoinTransactionPriority, memo: out.memo))
feeRate: feeRate); .toList(),
priority: priority as BitcoinTransactionPriority,
feeRate: bitcoinFeeRate
);
}
@override @override
Object createBitcoinTransactionCredentialsRaw(List<OutputInfo> outputs, Object createBitcoinTransactionCredentialsRaw(List<OutputInfo> outputs,
@ -172,8 +176,9 @@ class CWBitcoin extends Bitcoin {
int formatterStringDoubleToBitcoinAmount(String amount) => stringDoubleToBitcoinAmount(amount); int formatterStringDoubleToBitcoinAmount(String amount) => stringDoubleToBitcoinAmount(amount);
@override @override
String bitcoinTransactionPriorityWithLabel(TransactionPriority priority, int rate) => String bitcoinTransactionPriorityWithLabel(TransactionPriority priority, int rate,
(priority as BitcoinTransactionPriority).labelWithRate(rate); {int? customRate}) =>
(priority as BitcoinTransactionPriority).labelWithRate(rate, customRate);
@override @override
List<BitcoinUnspent> getUnspents(Object wallet) { List<BitcoinUnspent> getUnspents(Object wallet) {
@ -199,6 +204,9 @@ class CWBitcoin extends Bitcoin {
@override @override
TransactionPriority getBitcoinTransactionPriorityMedium() => BitcoinTransactionPriority.medium; TransactionPriority getBitcoinTransactionPriorityMedium() => BitcoinTransactionPriority.medium;
@override
TransactionPriority getBitcoinTransactionPriorityCustom() => BitcoinTransactionPriority.custom;
@override @override
TransactionPriority getLitecoinTransactionPriorityMedium() => LitecoinTransactionPriority.medium; TransactionPriority getLitecoinTransactionPriorityMedium() => LitecoinTransactionPriority.medium;
@ -244,4 +252,43 @@ class CWBitcoin extends Bitcoin {
bool hasTaprootInput(PendingTransaction pendingTransaction) { bool hasTaprootInput(PendingTransaction pendingTransaction) {
return (pendingTransaction as PendingBitcoinTransaction).hasTaprootInputs; return (pendingTransaction as PendingBitcoinTransaction).hasTaprootInputs;
} }
@override
Future<PendingBitcoinTransaction> replaceByFee(
Object wallet, String transactionHash, String fee) async {
final bitcoinWallet = wallet as ElectrumWallet;
return await bitcoinWallet.replaceByFee(transactionHash, int.parse(fee));
}
@override
Future<bool> canReplaceByFee(Object wallet, String transactionHash) async {
final bitcoinWallet = wallet as ElectrumWallet;
return bitcoinWallet.canReplaceByFee(transactionHash);
}
@override
Future<bool> isChangeSufficientForFee(Object wallet, String txId, String newFee) async {
final bitcoinWallet = wallet as ElectrumWallet;
return bitcoinWallet.isChangeSufficientForFee(txId, int.parse(newFee));
}
@override
int getFeeAmountForPriority(
Object wallet, TransactionPriority priority, int inputsCount, int outputsCount,
{int? size}) {
final bitcoinWallet = wallet as ElectrumWallet;
return bitcoinWallet.feeAmountForPriority(
priority as BitcoinTransactionPriority, inputsCount, outputsCount);
}
@override
int getFeeAmountWithFeeRate(Object wallet, int feeRate, int inputsCount, int outputsCount,
{int? size}) {
final bitcoinWallet = wallet as ElectrumWallet;
return bitcoinWallet.feeAmountWithFeeRate(
feeRate,
inputsCount,
outputsCount,
);
}
} }

View file

@ -155,7 +155,7 @@ class MoonPayProvider extends BuyProvider {
'baseCurrencyAmount': amount ?? '0', 'baseCurrencyAmount': amount ?? '0',
'currencyCode': currencyCode, 'currencyCode': currencyCode,
'walletAddress': walletAddress, 'walletAddress': walletAddress,
'lockAmount': 'true', 'lockAmount': 'false',
'showAllCurrencies': 'false', 'showAllCurrencies': 'false',
'showWalletAddressForm': 'false', 'showWalletAddressForm': 'false',
'enabledPaymentMethods': 'enabledPaymentMethods':
@ -256,44 +256,44 @@ class MoonPayProvider extends BuyProvider {
@override @override
Future<void> launchProvider(BuildContext context, bool? isBuyAction) async { Future<void> launchProvider(BuildContext context, bool? isBuyAction) async {
// try { try {
late final Uri uri; late final Uri uri;
if (isBuyAction ?? true) { if (isBuyAction ?? true) {
uri = await requestBuyMoonPayUrl( uri = await requestBuyMoonPayUrl(
currency: wallet.currency, currency: wallet.currency,
walletAddress: wallet.walletAddresses.address, walletAddress: wallet.walletAddresses.address,
settingsStore: _settingsStore, settingsStore: _settingsStore,
); );
} else {
uri = await requestSellMoonPayUrl(
currency: wallet.currency,
refundWalletAddress: wallet.walletAddresses.address,
settingsStore: _settingsStore,
);
}
if (await canLaunchUrl(uri)) {
if (DeviceInfo.instance.isMobile) {
Navigator.of(context).pushNamed(Routes.webViewPage, arguments: ['MoonPay', uri]);
} else { } else {
await launchUrl(uri, mode: LaunchMode.externalApplication); uri = await requestSellMoonPayUrl(
currency: wallet.currency,
refundWalletAddress: wallet.walletAddresses.address,
settingsStore: _settingsStore,
);
} }
} else {
throw Exception('Could not launch URL'); if (await canLaunchUrl(uri)) {
if (DeviceInfo.instance.isMobile) {
Navigator.of(context).pushNamed(Routes.webViewPage, arguments: ['MoonPay', uri]);
} else {
await launchUrl(uri, mode: LaunchMode.externalApplication);
}
} else {
throw Exception('Could not launch URL');
}
} catch (e) {
await showDialog<void>(
context: context,
builder: (BuildContext context) {
return AlertWithOneAction(
alertTitle: 'MoonPay',
alertContent: 'The MoonPay service is currently unavailable: $e',
buttonText: S.of(context).ok,
buttonAction: () => Navigator.of(context).pop(),
);
},
);
} }
// } catch (e) {
// await showDialog<void>(
// context: context,
// builder: (BuildContext context) {
// return AlertWithOneAction(
// alertTitle: 'MoonPay',
// alertContent: 'The MoonPay service is currently unavailable: $e',
// buttonText: S.of(context).ok,
// buttonAction: () => Navigator.of(context).pop(),
// );
// },
// );
// }
} }
String _normalizeCurrency(CryptoCurrency currency) { String _normalizeCurrency(CryptoCurrency currency) {

View file

@ -14,4 +14,13 @@ class FailureState extends ExecutionState {
FailureState(this.error); FailureState(this.error);
final String error; final String error;
}
class AwaitingConfirmationState extends ExecutionState {
AwaitingConfirmationState({this.title, this.message, this.onConfirm, this.onCancel});
final String? title;
final String? message;
final Function()? onConfirm;
final Function()? onCancel;
} }

View file

@ -8,3 +8,8 @@ class NodeAddressValidator extends TextValidator {
pattern: pattern:
'^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\$|^[0-9a-zA-Z.\-]+\$'); '^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\$|^[0-9a-zA-Z.\-]+\$');
} }
class NodePathValidator extends TextValidator {
NodePathValidator()
: super(errorMessage: S.current.error_text_node_address, pattern: '^([/0-9a-zA-Z.\-]+)?\$');
}

View file

@ -2,8 +2,8 @@ import 'solana_chain_service.dart';
enum SolanaChainId { enum SolanaChainId {
mainnet, mainnet,
testnet, // testnet,
devnet, // devnet,
} }
extension SolanaChainIdX on SolanaChainId { extension SolanaChainIdX on SolanaChainId {
@ -13,13 +13,16 @@ extension SolanaChainIdX on SolanaChainId {
switch (this) { switch (this) {
case SolanaChainId.mainnet: case SolanaChainId.mainnet:
name = '4sGjMW1sUnHzSxGspuhpqLDx6wiyjNtZ'; name = '4sGjMW1sUnHzSxGspuhpqLDx6wiyjNtZ';
// solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp
break; break;
case SolanaChainId.testnet: // case SolanaChainId.devnet:
name = '8E9rvCKLFQia2Y35HXjjpWzj8weVo44K'; // name = '8E9rvCKLFQia2Y35HXjjpWzj8weVo44K';
break; // // solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1
case SolanaChainId.devnet: // break;
name = ''; // case SolanaChainId.testnet:
break; // name = '';
// // solana:4uhcVJyU9pJkvQyS88uRDiswHXSCkY3z
// break;
} }
return '${SolanaChainServiceImpl.namespace}:$name'; return '${SolanaChainServiceImpl.namespace}:$name';

View file

@ -43,7 +43,7 @@ class SolanaChainServiceImpl implements ChainService {
SolanaClient( SolanaClient(
rpcUrl: rpcUrl, rpcUrl: rpcUrl,
websocketUrl: Uri.parse(webSocketUrl), websocketUrl: Uri.parse(webSocketUrl),
timeout: const Duration(minutes: 2), timeout: const Duration(minutes: 5),
) { ) {
for (final String event in getEvents()) { for (final String event in getEvents()) {
wallet.registerEventEmitter(chainId: getChainId(), event: event); wallet.registerEventEmitter(chainId: getChainId(), event: event);
@ -72,7 +72,7 @@ class SolanaChainServiceImpl implements ChainService {
@override @override
List<String> getEvents() { List<String> getEvents() {
return ['']; return ['chainChanged', 'accountsChanged'];
} }
Future<String?> requestAuthorization(String? text) async { Future<String?> requestAuthorization(String? text) async {
@ -100,8 +100,7 @@ class SolanaChainServiceImpl implements ChainService {
Future<String> solanaSignTransaction(String topic, dynamic parameters) async { Future<String> solanaSignTransaction(String topic, dynamic parameters) async {
log('received solana sign transaction request $parameters'); log('received solana sign transaction request $parameters');
final solanaSignTx = final solanaSignTx = SolanaSignTransaction.fromJson(parameters as Map<String, dynamic>);
SolanaSignTransaction.fromJson(parameters as Map<String, dynamic>);
final String? authError = await requestAuthorization('Confirm request to sign transaction?'); final String? authError = await requestAuthorization('Confirm request to sign transaction?');
@ -122,10 +121,13 @@ class SolanaChainServiceImpl implements ChainService {
return ''; return '';
} }
String signature = sign.signatures.first.toBase58(); String signature = await solanaClient.sendAndConfirmTransaction(
message: message,
signers: [ownerKeyPair!],
commitment: Commitment.confirmed,
);
print(signature); print(signature);
print(signature.runtimeType);
bottomSheetService.queueBottomSheet( bottomSheetService.queueBottomSheet(
isModalDismissible: true, isModalDismissible: true,

View file

@ -1,10 +1,12 @@
import 'dart:async'; import 'dart:async';
import 'dart:convert';
import 'dart:developer'; import 'dart:developer';
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:cake_wallet/core/wallet_connect/chain_service/eth/evm_chain_id.dart'; import 'package:cake_wallet/core/wallet_connect/chain_service/eth/evm_chain_id.dart';
import 'package:cake_wallet/core/wallet_connect/chain_service/eth/evm_chain_service.dart'; import 'package:cake_wallet/core/wallet_connect/chain_service/eth/evm_chain_service.dart';
import 'package:cake_wallet/core/wallet_connect/wallet_connect_key_service.dart'; import 'package:cake_wallet/core/wallet_connect/wallet_connect_key_service.dart';
import 'package:cake_wallet/entities/preferences_key.dart';
import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/core/wallet_connect/models/auth_request_model.dart'; import 'package:cake_wallet/core/wallet_connect/models/auth_request_model.dart';
import 'package:cake_wallet/core/wallet_connect/models/chain_key_model.dart'; import 'package:cake_wallet/core/wallet_connect/models/chain_key_model.dart';
@ -19,6 +21,7 @@ import 'package:cw_core/wallet_type.dart';
import 'package:eth_sig_util/eth_sig_util.dart'; import 'package:eth_sig_util/eth_sig_util.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:mobx/mobx.dart'; import 'package:mobx/mobx.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:walletconnect_flutter_v2/walletconnect_flutter_v2.dart'; import 'package:walletconnect_flutter_v2/walletconnect_flutter_v2.dart';
import 'chain_service/solana/solana_chain_id.dart'; import 'chain_service/solana/solana_chain_id.dart';
@ -32,6 +35,7 @@ class Web3WalletService = Web3WalletServiceBase with _$Web3WalletService;
abstract class Web3WalletServiceBase with Store { abstract class Web3WalletServiceBase with Store {
final AppStore appStore; final AppStore appStore;
final SharedPreferences sharedPreferences;
final BottomSheetService _bottomSheetHandler; final BottomSheetService _bottomSheetHandler;
final WalletConnectKeyService walletKeyService; final WalletConnectKeyService walletKeyService;
@ -52,7 +56,8 @@ abstract class Web3WalletServiceBase with Store {
@observable @observable
ObservableList<StoredCacao> auth; ObservableList<StoredCacao> auth;
Web3WalletServiceBase(this._bottomSheetHandler, this.walletKeyService, this.appStore) Web3WalletServiceBase(
this._bottomSheetHandler, this.walletKeyService, this.appStore, this.sharedPreferences)
: pairings = ObservableList<PairingInfo>(), : pairings = ObservableList<PairingInfo>(),
sessions = ObservableList<SessionData>(), sessions = ObservableList<SessionData>(),
auth = ObservableList<StoredCacao>(), auth = ObservableList<StoredCacao>(),
@ -133,13 +138,27 @@ abstract class Web3WalletServiceBase with Store {
if (appStore.wallet!.type == WalletType.solana) { if (appStore.wallet!.type == WalletType.solana) {
for (final cId in SolanaChainId.values) { for (final cId in SolanaChainId.values) {
final node = appStore.settingsStore.getCurrentNode(appStore.wallet!.type); final node = appStore.settingsStore.getCurrentNode(appStore.wallet!.type);
final rpcUri = node.uri;
final webSocketUri = 'wss://${node.uriRaw}/ws${node.uri.path}'; Uri? rpcUri;
String webSocketUrl;
bool isModifiedNodeUri = false;
if (node.uriRaw == 'rpc.ankr.com') {
isModifiedNodeUri = true;
//A better way to handle this instead of adding this to the general secrets?
String ankrApiKey = secrets.ankrApiKey;
rpcUri = Uri.https(node.uriRaw, '/solana/$ankrApiKey');
webSocketUrl = 'wss://${node.uriRaw}/solana/ws/$ankrApiKey';
} else {
webSocketUrl = 'wss://${node.uriRaw}';
}
SolanaChainServiceImpl( SolanaChainServiceImpl(
reference: cId, reference: cId,
rpcUrl: rpcUri, rpcUrl: isModifiedNodeUri ? rpcUri! : node.uri,
webSocketUrl: webSocketUri, webSocketUrl: webSocketUrl,
wcKeyService: walletKeyService, wcKeyService: walletKeyService,
bottomSheetService: _bottomSheetHandler, bottomSheetService: _bottomSheetHandler,
wallet: _web3Wallet, wallet: _web3Wallet,
@ -177,13 +196,6 @@ abstract class Web3WalletServiceBase with Store {
_refreshPairings(); _refreshPairings();
} }
@action
void _refreshPairings() {
pairings.clear();
final allPairings = _web3Wallet.pairings.getAll();
pairings.addAll(allPairings);
}
Future<void> _onSessionProposalError(SessionProposalErrorEvent? args) async { Future<void> _onSessionProposalError(SessionProposalErrorEvent? args) async {
log(args.toString()); log(args.toString());
} }
@ -246,14 +258,37 @@ abstract class Web3WalletServiceBase with Store {
} }
} }
@action
void _refreshPairings() {
print('Refreshing pairings');
pairings.clear();
final allPairings = _web3Wallet.pairings.getAll();
final keyForWallet = getKeyForStoringTopicsForWallet();
final currentTopicsForWallet = getPairingTopicsForWallet(keyForWallet);
final filteredPairings =
allPairings.where((pairing) => currentTopicsForWallet.contains(pairing.topic)).toList();
pairings.addAll(filteredPairings);
}
void _onPairingCreate(PairingEvent? args) { void _onPairingCreate(PairingEvent? args) {
log('Pairing Create Event: $args'); log('Pairing Create Event: $args');
} }
@action @action
void _onSessionConnect(SessionConnect? args) { Future<void> _onSessionConnect(SessionConnect? args) async {
if (args != null) { if (args != null) {
log('Session Connected $args');
await savePairingTopicToLocalStorage(args.session.pairingTopic);
sessions.add(args.session); sessions.add(args.session);
_refreshPairings();
} }
} }
@ -321,4 +356,53 @@ abstract class Web3WalletServiceBase with Store {
List<SessionData> getSessionsForPairingInfo(PairingInfo pairing) { List<SessionData> getSessionsForPairingInfo(PairingInfo pairing) {
return sessions.where((element) => element.pairingTopic == pairing.topic).toList(); return sessions.where((element) => element.pairingTopic == pairing.topic).toList();
} }
String getKeyForStoringTopicsForWallet() {
List<ChainKeyModel> chainKeys = walletKeyService.getKeysForChain(appStore.wallet!);
final keyForPairingTopic =
PreferencesKey.walletConnectPairingTopicsListForWallet(chainKeys.first.publicKey);
return keyForPairingTopic;
}
List<String> getPairingTopicsForWallet(String key) {
// Get the JSON-encoded string from shared preferences
final jsonString = sharedPreferences.getString(key);
// If the string is null, return an empty list
if (jsonString == null) {
return [];
}
// Decode the JSON string to a list of strings
final List<dynamic> jsonList = jsonDecode(jsonString) as List<dynamic>;
// Cast each item to a string
return jsonList.map((item) => item as String).toList();
}
Future<void> savePairingTopicToLocalStorage(String pairingTopic) async {
// Get key specific to the current wallet
final key = getKeyForStoringTopicsForWallet();
// Get all pairing topics attached to this key
final pairingTopicsForWallet = getPairingTopicsForWallet(key);
print(pairingTopicsForWallet);
bool isPairingTopicAlreadySaved = pairingTopicsForWallet.contains(pairingTopic);
print('Is Pairing Topic Saved: $isPairingTopicAlreadySaved');
if (!isPairingTopicAlreadySaved) {
// Update the list with the most recent pairing topic
pairingTopicsForWallet.add(pairingTopic);
// Convert the list of updated pairing topics to a JSON-encoded string
final jsonString = jsonEncode(pairingTopicsForWallet);
// Save the encoded string to shared preferences
await sharedPreferences.setString(key, jsonString);
}
}
} }

View file

@ -15,6 +15,7 @@ import 'package:cake_wallet/entities/background_tasks.dart';
import 'package:cake_wallet/entities/exchange_api_mode.dart'; import 'package:cake_wallet/entities/exchange_api_mode.dart';
import 'package:cake_wallet/entities/parse_address_from_domain.dart'; import 'package:cake_wallet/entities/parse_address_from_domain.dart';
import 'package:cake_wallet/view_model/lightning_send_view_model.dart'; import 'package:cake_wallet/view_model/lightning_send_view_model.dart';
import 'package:cake_wallet/src/screens/transaction_details/rbf_details_page.dart';
import 'package:cw_core/receive_page_option.dart'; import 'package:cw_core/receive_page_option.dart';
import 'package:cake_wallet/ethereum/ethereum.dart'; import 'package:cake_wallet/ethereum/ethereum.dart';
import 'package:cake_wallet/lightning/lightning.dart'; import 'package:cake_wallet/lightning/lightning.dart';
@ -504,6 +505,7 @@ Future<void> setup({
getIt.get<BottomSheetService>(), getIt.get<BottomSheetService>(),
getIt.get<WalletConnectKeyService>(), getIt.get<WalletConnectKeyService>(),
appStore, appStore,
getIt.get<SharedPreferences>()
); );
web3WalletService.create(); web3WalletService.create();
return web3WalletService; return web3WalletService;
@ -927,7 +929,8 @@ Future<void> setup({
transactionInfo: transactionInfo, transactionInfo: transactionInfo,
transactionDescriptionBox: _transactionDescriptionBox, transactionDescriptionBox: _transactionDescriptionBox,
wallet: wallet, wallet: wallet,
settingsStore: getIt.get<SettingsStore>()); settingsStore: getIt.get<SettingsStore>(),
sendViewModel: getIt.get<SendViewModel>());
}); });
getIt.registerFactoryParam<TransactionDetailsPage, TransactionInfo, void>( getIt.registerFactoryParam<TransactionDetailsPage, TransactionInfo, void>(
@ -1150,6 +1153,11 @@ Future<void> setup({
getIt.registerFactory(() => IoniaAccountCardsPage(getIt.get<IoniaAccountViewModel>())); getIt.registerFactory(() => IoniaAccountCardsPage(getIt.get<IoniaAccountViewModel>()));
getIt.registerFactoryParam<RBFDetailsPage, TransactionInfo, void>(
(TransactionInfo transactionInfo, _) => RBFDetailsPage(
transactionDetailsViewModel:
getIt.get<TransactionDetailsViewModel>(param1: transactionInfo)));
getIt.registerFactory(() => AnonPayApi( getIt.registerFactory(() => AnonPayApi(
useTorOnly: getIt.get<SettingsStore>().exchangeStatus == ExchangeApiMode.torOnly, useTorOnly: getIt.get<SettingsStore>().exchangeStatus == ExchangeApiMode.torOnly,
wallet: getIt.get<AppStore>().wallet!)); wallet: getIt.get<AppStore>().wallet!));

View file

@ -216,6 +216,10 @@ Future<void> defaultSettingsMigration(
await disableServiceStatusFiatDisabled(sharedPreferences); await disableServiceStatusFiatDisabled(sharedPreferences);
break; break;
case 31:
await updateNanoNodeList(nodes: nodes);
break;
default: default:
break; break;
} }
@ -230,14 +234,40 @@ Future<void> defaultSettingsMigration(
await sharedPreferences.setInt(PreferencesKey.currentDefaultSettingsMigrationVersion, version); await sharedPreferences.setInt(PreferencesKey.currentDefaultSettingsMigrationVersion, version);
} }
Future<void> updateNanoNodeList({required Box<Node> nodes}) async {
final nodeList = await loadDefaultNanoNodes();
var listOfNewEndpoints = <String>[
"app.natrium.io",
"rainstorm.city",
"node.somenano.com",
"nanoslo.0x.no",
"www.bitrequest.app",
];
// add new nodes:
for (final node in nodeList) {
if (listOfNewEndpoints.contains(node.uriRaw)) {
await nodes.add(node);
}
}
// update the nautilus node:
final nautilusNode =
nodes.values.firstWhereOrNull((element) => element.uriRaw == "node.perish.co");
if (nautilusNode != null) {
nautilusNode.uriRaw = "node.nautilus.io";
nautilusNode.path = "/api";
nautilusNode.useSSL = true;
await nautilusNode.save();
}
}
Future<void> disableServiceStatusFiatDisabled(SharedPreferences sharedPreferences) async { Future<void> disableServiceStatusFiatDisabled(SharedPreferences sharedPreferences) async {
final currentFiat = final currentFiat = await sharedPreferences.getInt(PreferencesKey.currentFiatApiModeKey) ?? -1;
await sharedPreferences.getInt(PreferencesKey.currentFiatApiModeKey) ?? -1;
if (currentFiat == -1 || currentFiat == FiatApiMode.enabled.raw) { if (currentFiat == -1 || currentFiat == FiatApiMode.enabled.raw) {
return; return;
} }
if (currentFiat == FiatApiMode.disabled.raw) { if (currentFiat == FiatApiMode.disabled.raw || currentFiat == FiatApiMode.torOnly.raw) {
await sharedPreferences.setBool(PreferencesKey.disableBulletinKey, true); await sharedPreferences.setBool(PreferencesKey.disableBulletinKey, true);
} }
} }

View file

@ -42,8 +42,10 @@ class PreferencesKey {
static const ethereumTransactionPriority = 'current_fee_priority_ethereum'; static const ethereumTransactionPriority = 'current_fee_priority_ethereum';
static const polygonTransactionPriority = 'current_fee_priority_polygon'; static const polygonTransactionPriority = 'current_fee_priority_polygon';
static const bitcoinCashTransactionPriority = 'current_fee_priority_bitcoin_cash'; static const bitcoinCashTransactionPriority = 'current_fee_priority_bitcoin_cash';
static const customBitcoinFeeRate = 'custom_electrum_fee_rate';
static const shouldShowReceiveWarning = 'should_show_receive_warning'; static const shouldShowReceiveWarning = 'should_show_receive_warning';
static const shouldShowYatPopup = 'should_show_yat_popup'; static const shouldShowYatPopup = 'should_show_yat_popup';
static const shouldShowRepWarning = 'should_show_rep_warning';
static const moneroWalletPasswordUpdateV1Base = 'monero_wallet_update_v1'; static const moneroWalletPasswordUpdateV1Base = 'monero_wallet_update_v1';
static const syncModeKey = 'sync_mode'; static const syncModeKey = 'sync_mode';
static const syncAllKey = 'sync_all'; static const syncAllKey = 'sync_all';
@ -74,4 +76,7 @@ class PreferencesKey {
static const shouldShowMarketPlaceInDashboard = 'should_show_marketplace_in_dashboard'; static const shouldShowMarketPlaceInDashboard = 'should_show_marketplace_in_dashboard';
static const isNewInstall = 'is_new_install'; static const isNewInstall = 'is_new_install';
static const serviceStatusShaKey = 'service_status_sha_key'; static const serviceStatusShaKey = 'service_status_sha_key';
static const walletConnectPairingTopicsList = 'wallet_connect_pairing_topics_list';
static String walletConnectPairingTopicsListForWallet(String publicKey) =>
'${PreferencesKey.walletConnectPairingTopicsList}_${publicKey}';
} }

View file

@ -131,7 +131,7 @@ class CWEthereum extends Ethereum {
@override @override
Future<Erc20Token?> getErc20Token(WalletBase wallet, String contractAddress) async { Future<Erc20Token?> getErc20Token(WalletBase wallet, String contractAddress) async {
final ethereumWallet = wallet as EthereumWallet; final ethereumWallet = wallet as EthereumWallet;
return await ethereumWallet.getErc20Token(contractAddress); return await ethereumWallet.getErc20Token(contractAddress, 'eth');
} }
@override @override

View file

@ -40,7 +40,17 @@ class TrocadorExchangeProvider extends ExchangeProvider {
'Exolix', 'Exolix',
'Godex', 'Godex',
'Exch', 'Exch',
'CoinCraddle' 'CoinCraddle',
'Alfacash',
'LocalMonero',
'XChange',
'NeroSwap',
'Changee',
'BitcoinVN',
'EasyBit',
'WizardSwap',
'Quantex',
'SwapSpace',
]; ];
static const List<CryptoCurrency> _notSupported = [ static const List<CryptoCurrency> _notSupported = [

View file

@ -163,7 +163,7 @@ Future<void> initializeAppConfigs() async {
transactionDescriptions: transactionDescriptions, transactionDescriptions: transactionDescriptions,
secureStorage: secureStorage, secureStorage: secureStorage,
anonpayInvoiceInfo: anonpayInvoiceInfo, anonpayInvoiceInfo: anonpayInvoiceInfo,
initialMigrationVersion: 30, initialMigrationVersion: 31,
); );
} }

View file

@ -186,6 +186,16 @@ class CWNano extends Nano {
String getRepresentative(Object wallet) { String getRepresentative(Object wallet) {
return (wallet as NanoWallet).representative; return (wallet as NanoWallet).representative;
} }
@override
Future<List<N2Node>> getN2Reps(Object wallet) async {
return (wallet as NanoWallet).getN2Reps();
}
@override
bool isRepOk(Object wallet) {
return (wallet as NanoWallet).isRepOk;
}
} }
class CWNanoUtil extends NanoUtil { class CWNanoUtil extends NanoUtil {

View file

@ -129,7 +129,7 @@ class CWPolygon extends Polygon {
@override @override
Future<Erc20Token?> getErc20Token(WalletBase wallet, String contractAddress) async { Future<Erc20Token?> getErc20Token(WalletBase wallet, String contractAddress) async {
final polygonWallet = wallet as PolygonWallet; final polygonWallet = wallet as PolygonWallet;
return await polygonWallet.getErc20Token(contractAddress); return await polygonWallet.getErc20Token(contractAddress, 'polygon');
} }
@override @override

View file

@ -16,6 +16,7 @@ bool isWalletConnectCompatibleChain(WalletType walletType) {
switch (walletType) { switch (walletType) {
case WalletType.polygon: case WalletType.polygon:
case WalletType.ethereum: case WalletType.ethereum:
case WalletType.solana:
return true; return true;
default: default:
return false; return false;

View file

@ -58,6 +58,7 @@ import 'package:cake_wallet/src/screens/setup_2fa/setup_2fa_enter_code_page.dart
import 'package:cake_wallet/src/screens/support/support_page.dart'; import 'package:cake_wallet/src/screens/support/support_page.dart';
import 'package:cake_wallet/src/screens/support_chat/support_chat_page.dart'; import 'package:cake_wallet/src/screens/support_chat/support_chat_page.dart';
import 'package:cake_wallet/src/screens/support_other_links/support_other_links_page.dart'; import 'package:cake_wallet/src/screens/support_other_links/support_other_links_page.dart';
import 'package:cake_wallet/src/screens/transaction_details/rbf_details_page.dart';
import 'package:cake_wallet/src/screens/unspent_coins/unspent_coins_details_page.dart'; import 'package:cake_wallet/src/screens/unspent_coins/unspent_coins_details_page.dart';
import 'package:cake_wallet/src/screens/unspent_coins/unspent_coins_list_page.dart'; import 'package:cake_wallet/src/screens/unspent_coins/unspent_coins_list_page.dart';
import 'package:cake_wallet/src/screens/wallet_connect/wc_connections_listing_view.dart'; import 'package:cake_wallet/src/screens/wallet_connect/wc_connections_listing_view.dart';
@ -258,6 +259,12 @@ Route<dynamic> createRoute(RouteSettings settings) {
builder: (_) => builder: (_) =>
getIt.get<TransactionDetailsPage>(param1: settings.arguments as TransactionInfo)); getIt.get<TransactionDetailsPage>(param1: settings.arguments as TransactionInfo));
case Routes.bumpFeePage:
return CupertinoPageRoute<void>(
fullscreenDialog: true,
builder: (_) =>
getIt.get<RBFDetailsPage>(param1: settings.arguments as TransactionInfo));
case Routes.newSubaddress: case Routes.newSubaddress:
return CupertinoPageRoute<void>( return CupertinoPageRoute<void>(
builder: (_) => getIt.get<AddressEditOrCreatePage>(param1: settings.arguments)); builder: (_) => getIt.get<AddressEditOrCreatePage>(param1: settings.arguments));

View file

@ -12,6 +12,7 @@ class Routes {
static const dashboard = '/dashboard'; static const dashboard = '/dashboard';
static const send = '/send'; static const send = '/send';
static const transactionDetails = '/transaction_info'; static const transactionDetails = '/transaction_info';
static const bumpFeePage = '/bump_fee_page';
static const receive = '/receive'; static const receive = '/receive';
static const newSubaddress = '/new_subaddress'; static const newSubaddress = '/new_subaddress';
static const walletEdit = '/walletEdit'; static const walletEdit = '/walletEdit';

View file

@ -86,6 +86,7 @@ class CWSolana extends Solana {
decimal: token.decimals, decimal: token.decimals,
mint: token.name.toUpperCase(), mint: token.name.toUpperCase(),
enabled: token.enabled, enabled: token.enabled,
iconPath: token.iconPath,
); );
await (wallet as SolanaWallet).addSPLToken(splToken); await (wallet as SolanaWallet).addSPLToken(splToken);

View file

@ -59,6 +59,7 @@ class _EditTokenPageBodyState extends State<EditTokenPageBody> {
final TextEditingController _tokenNameController = TextEditingController(); final TextEditingController _tokenNameController = TextEditingController();
final TextEditingController _tokenSymbolController = TextEditingController(); final TextEditingController _tokenSymbolController = TextEditingController();
final TextEditingController _tokenDecimalController = TextEditingController(); final TextEditingController _tokenDecimalController = TextEditingController();
final TextEditingController _tokenIconPathController = TextEditingController();
final FocusNode _contractAddressFocusNode = FocusNode(); final FocusNode _contractAddressFocusNode = FocusNode();
final FocusNode _tokenNameFocusNode = FocusNode(); final FocusNode _tokenNameFocusNode = FocusNode();
@ -83,6 +84,7 @@ class _EditTokenPageBodyState extends State<EditTokenPageBody> {
_tokenNameController.text = widget.token!.name; _tokenNameController.text = widget.token!.name;
_tokenSymbolController.text = widget.token!.title; _tokenSymbolController.text = widget.token!.title;
_tokenDecimalController.text = widget.token!.decimals.toString(); _tokenDecimalController.text = widget.token!.decimals.toString();
_tokenIconPathController.text = widget.token?.iconPath ?? '';
} }
if (widget.initialContractAddress != null) { if (widget.initialContractAddress != null) {
@ -200,6 +202,7 @@ class _EditTokenPageBodyState extends State<EditTokenPageBody> {
name: _tokenNameController.text, name: _tokenNameController.text,
title: _tokenSymbolController.text.toUpperCase(), title: _tokenSymbolController.text.toUpperCase(),
decimals: int.parse(_tokenDecimalController.text), decimals: int.parse(_tokenDecimalController.text),
iconPath: _tokenIconPathController.text,
), ),
contractAddress: _contractAddressController.text, contractAddress: _contractAddressController.text,
); );
@ -228,6 +231,8 @@ class _EditTokenPageBodyState extends State<EditTokenPageBody> {
if (token != null) { if (token != null) {
if (_tokenNameController.text.isEmpty) _tokenNameController.text = token.name; if (_tokenNameController.text.isEmpty) _tokenNameController.text = token.name;
if (_tokenSymbolController.text.isEmpty) _tokenSymbolController.text = token.title; if (_tokenSymbolController.text.isEmpty) _tokenSymbolController.text = token.title;
if (_tokenIconPathController.text.isEmpty)
_tokenIconPathController.text = token.iconPath ?? '';
if (_tokenDecimalController.text.isEmpty) if (_tokenDecimalController.text.isEmpty)
_tokenDecimalController.text = token.decimals.toString(); _tokenDecimalController.text = token.decimals.toString();
} }
@ -305,10 +310,15 @@ class _EditTokenPageBodyState extends State<EditTokenPageBody> {
if (text?.isEmpty ?? true) { if (text?.isEmpty ?? true) {
return S.of(context).field_required; return S.of(context).field_required;
} }
if (int.tryParse(text!) == null) { if (int.tryParse(text!) == null) {
return S.of(context).invalid_input; return S.of(context).invalid_input;
} }
if (int.tryParse(text) == 0) {
return S.current.decimals_cannot_be_zero;
}
return null; return null;
}, },
), ),

View file

@ -129,25 +129,29 @@ class HomeSettingsPage extends BasePage {
'token': token, 'token': token,
}); });
}, },
leading: CakeImageWidget( leading: Container(
imageUrl: token.iconPath, clipBehavior: Clip.hardEdge,
height: 40, decoration: BoxDecoration(shape: BoxShape.circle),
width: 40, child: CakeImageWidget(
displayOnError: Container( imageUrl: token.iconPath,
height: 30.0, height: 40,
width: 30.0, width: 40,
child: Center( displayOnError: Container(
child: Text( height: 30.0,
token.title.substring(0, min(token.title.length, 2)), width: 30.0,
style: TextStyle(fontSize: 11), child: Center(
), child: Text(
), token.title.substring(0, min(token.title.length, 2)),
decoration: BoxDecoration( style: TextStyle(fontSize: 11),
shape: BoxShape.circle,
color: Colors.grey.shade400,
), ),
),
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Colors.grey.shade400,
),
),
), ),
), ),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Theme.of(context).cardColor, color: Theme.of(context).cardColor,
borderRadius: BorderRadius.circular(30), borderRadius: BorderRadius.circular(30),

View file

@ -163,12 +163,7 @@ class AddressPage extends BasePage {
if (addressListViewModel.hasAddressList) { if (addressListViewModel.hasAddressList) {
return SelectButton( return SelectButton(
text: addressListViewModel.buttonTitle, text: addressListViewModel.buttonTitle,
onTap: () async => dashboardViewModel.isAutoGenerateSubaddressesEnabled && onTap: () async => Navigator.of(context).pushNamed(Routes.receive),
(WalletType.monero == addressListViewModel.wallet.type ||
WalletType.haven == addressListViewModel.wallet.type)
? await showPopUp<void>(
context: context, builder: (_) => getIt.get<MoneroAccountListPage>())
: Navigator.of(context).pushNamed(Routes.receive),
textColor: Theme.of(context).extension<SyncIndicatorTheme>()!.textColor, textColor: Theme.of(context).extension<SyncIndicatorTheme>()!.textColor,
color: Theme.of(context).extension<SyncIndicatorTheme>()!.syncedBackgroundColor, color: Theme.of(context).extension<SyncIndicatorTheme>()!.syncedBackgroundColor,
borderColor: Theme.of(context).extension<BalancePageTheme>()!.cardBorderColor, borderColor: Theme.of(context).extension<BalancePageTheme>()!.cardBorderColor,
@ -176,17 +171,11 @@ class AddressPage extends BasePage {
textSize: 14, textSize: 14,
height: 50, height: 50,
); );
} else if (dashboardViewModel.isAutoGenerateSubaddressesEnabled || }
addressListViewModel.isElectrumWallet) { else {
return Text(S.of(context).electrum_address_disclaimer,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 15,
color: Theme.of(context).extension<BalancePageTheme>()!.labelTextColor));
} else {
return const SizedBox(); return const SizedBox();
} }
}) }),
], ],
), ),
)); ));

View file

@ -198,6 +198,22 @@ class CryptoBalanceWidget extends StatelessWidget {
return Container(); return Container();
}, },
), ),
Observer(builder: (_) {
if (!dashboardViewModel.showRepWarning) {
return const SizedBox();
}
return Padding(
padding: const EdgeInsets.fromLTRB(16, 0, 16, 8),
child: DashBoardRoundedCardWidget(
title: S.current.rep_warning,
subTitle: S.current.rep_warning_sub,
onTap: () => Navigator.of(context).pushNamed(Routes.changeRep),
onClose: () {
dashboardViewModel.settingsStore.shouldShowRepWarning = false;
},
),
);
}),
Observer( Observer(
builder: (_) { builder: (_) {
return ListView.separated( return ListView.separated(
@ -338,7 +354,7 @@ class BalanceRowWidget extends StatelessWidget {
style: TextStyle( style: TextStyle(
fontSize: 16, fontSize: 16,
fontFamily: 'Lato', fontFamily: 'Lato',
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
color: Theme.of(context).extension<BalancePageTheme>()!.textColor, color: Theme.of(context).extension<BalancePageTheme>()!.textColor,
height: 1)), height: 1)),
], ],
@ -349,22 +365,26 @@ class BalanceRowWidget extends StatelessWidget {
child: Center( child: Center(
child: Column( child: Column(
children: [ children: [
CakeImageWidget( Container(
imageUrl: currency.iconPath, clipBehavior: Clip.antiAlias,
height: 40, decoration: BoxDecoration(shape: BoxShape.circle),
width: 40, child: CakeImageWidget(
displayOnError: Container( imageUrl: currency.iconPath,
height: 30.0, height: 40,
width: 30.0, width: 40,
child: Center( displayOnError: Container(
child: Text( height: 30.0,
currency.title.substring(0, min(currency.title.length, 2)), width: 30.0,
style: TextStyle(fontSize: 11), child: Center(
child: Text(
currency.title.substring(0, min(currency.title.length, 2)),
style: TextStyle(fontSize: 11),
),
),
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Colors.grey.shade400,
), ),
),
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Colors.grey.shade400,
), ),
), ),
), ),

View file

@ -5,10 +5,12 @@ import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart'; import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
import 'package:cake_wallet/store/settings_store.dart'; import 'package:cake_wallet/store/settings_store.dart';
import 'package:cake_wallet/themes/extensions/address_theme.dart'; import 'package:cake_wallet/themes/extensions/address_theme.dart';
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
import 'package:cake_wallet/utils/payment_request.dart'; import 'package:cake_wallet/utils/payment_request.dart';
import 'package:cake_wallet/utils/show_pop_up.dart'; import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:cw_core/crypto_currency.dart'; import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/wallet_base.dart'; import 'package:cw_core/wallet_base.dart';
import 'package:cw_core/n2_node.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/generated/i18n.dart';
@ -21,9 +23,7 @@ class NanoChangeRepPage extends BasePage {
: _wallet = wallet, : _wallet = wallet,
_settingsStore = settingsStore, _settingsStore = settingsStore,
_addressController = TextEditingController(), _addressController = TextEditingController(),
_formKey = GlobalKey<FormState>() { _formKey = GlobalKey<FormState>() {}
_addressController.text = nano!.getRepresentative(wallet);
}
final TextEditingController _addressController; final TextEditingController _addressController;
final WalletBase _wallet; final WalletBase _wallet;
@ -34,105 +34,314 @@ class NanoChangeRepPage extends BasePage {
@override @override
String get title => S.current.change_rep; String get title => S.current.change_rep;
N2Node getCurrentRepNode(List<N2Node> nodes) {
final currentRepAccount = nano!.getRepresentative(_wallet);
final currentNode = nodes.firstWhere(
(node) => node.account == currentRepAccount,
orElse: () => N2Node(
account: currentRepAccount,
alias: currentRepAccount,
score: 0,
uptime: "???",
weight: 0,
),
);
return currentNode;
}
@override @override
Widget body(BuildContext context) { Widget body(BuildContext context) {
return Form( return Form(
key: _formKey, key: _formKey,
child: Container( child: FutureBuilder(
padding: EdgeInsets.only(left: 24, right: 24), future: nano!.getN2Reps(_wallet),
child: ScrollableWithBottomSection( builder: (context, snapshot) {
contentPadding: EdgeInsets.only(bottom: 24.0), if (snapshot.data == null) {
content: Container( return SizedBox();
child: Column( }
children: <Widget>[
Row( return Container(
children: <Widget>[ padding: EdgeInsets.only(left: 24, right: 24),
Expanded( child: ScrollableWithBottomSection(
child: AddressTextField( topSectionPadding: EdgeInsets.only(bottom: 24),
controller: _addressController, topSection: Column(
onURIScanned: (uri) { children: [
final paymentRequest = PaymentRequest.fromUri(uri); Row(
_addressController.text = paymentRequest.address; children: <Widget>[
}, Expanded(
options: [ child: AddressTextField(
AddressTextFieldOption.paste, controller: _addressController,
AddressTextFieldOption.qrCode, onURIScanned: (uri) {
], final paymentRequest = PaymentRequest.fromUri(uri);
buttonColor: Theme.of(context).extension<AddressTheme>()!.actionButtonColor, _addressController.text = paymentRequest.address;
validator: AddressValidator(type: CryptoCurrency.nano), },
options: [
AddressTextFieldOption.paste,
AddressTextFieldOption.qrCode,
],
buttonColor:
Theme.of(context).extension<AddressTheme>()!.actionButtonColor,
validator: AddressValidator(type: CryptoCurrency.nano),
),
)
],
),
Column(
children: [
Container(
margin: EdgeInsets.only(top: 12),
child: Text(
S.current.nano_current_rep,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w700,
),
),
), ),
) _buildSingleRepresentative(
], context,
getCurrentRepNode(snapshot.data as List<N2Node>),
isList: false,
),
Divider(height: 20),
Container(
margin: EdgeInsets.only(top: 12),
child: Text(
S.current.nano_pick_new_rep,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w700,
),
),
),
],
),
],
),
contentPadding: EdgeInsets.only(bottom: 24),
content: Container(
child: Column(
children: _getRepresentativeWidgets(context, snapshot.data as List<N2Node>),
),
),
bottomSectionPadding: EdgeInsets.only(bottom: 24),
bottomSection: Observer(
builder: (_) => Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Flexible(
child: Container(
padding: EdgeInsets.only(right: 8.0),
child: LoadingPrimaryButton(
onPressed: () => _onSubmit(context),
text: S.of(context).change,
color: Theme.of(context).primaryColor,
textColor: Colors.white,
),
)),
],
)),
),
);
},
),
);
}
Future<void> _onSubmit(BuildContext context) async {
if (_formKey.currentState != null && !_formKey.currentState!.validate()) {
return;
}
final confirmed = await showPopUp<bool>(
context: context,
builder: (BuildContext context) {
return AlertWithTwoActions(
alertTitle: S.of(context).change_rep,
alertContent: S.of(context).change_rep_message,
rightButtonText: S.of(context).change,
leftButtonText: S.of(context).cancel,
actionRightButton: () => Navigator.pop(context, true),
actionLeftButton: () => Navigator.pop(context, false));
}) ??
false;
if (confirmed) {
try {
_settingsStore.defaultNanoRep = _addressController.text;
await nano!.changeRep(_wallet, _addressController.text);
// reset this flag whenever we successfully change reps:
_settingsStore.shouldShowRepWarning = true;
await showPopUp<void>(
context: context,
builder: (BuildContext context) {
return AlertWithOneAction(
alertTitle: S.of(context).successful,
alertContent: S.of(context).change_rep_successful,
buttonText: S.of(context).ok,
buttonAction: () => Navigator.pop(context));
});
} catch (e) {
await showPopUp<void>(
context: context,
builder: (BuildContext context) {
return AlertWithOneAction(
alertTitle: S.of(context).error,
alertContent: e.toString(),
buttonText: S.of(context).ok,
buttonAction: () => Navigator.pop(context));
});
throw e;
}
}
}
List<Widget> _getRepresentativeWidgets(BuildContext context, List<N2Node>? list) {
if (list == null) {
return [];
}
final List<Widget> ret = [];
for (final N2Node node in list) {
if (node.alias != null && node.alias!.trim().isNotEmpty) {
ret.add(_buildSingleRepresentative(context, node));
}
}
return ret;
}
Widget _buildSingleRepresentative(BuildContext context, N2Node rep, {bool isList = true}) {
return Column(
children: <Widget>[
if (isList)
Divider(
height: 2,
),
TextButton(
style: TextButton.styleFrom(
padding: EdgeInsets.zero,
),
onPressed: () async {
if (!isList) {
return;
}
_addressController.text = rep.account!;
},
child: Container(
margin: const EdgeInsets.symmetric(vertical: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Container(
margin: const EdgeInsetsDirectional.only(start: 24),
width: MediaQuery.of(context).size.width * 0.50,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
_sanitizeAlias(rep.alias),
style: TextStyle(
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
fontWeight: FontWeight.w700,
fontSize: 18,
),
),
Container(
margin: const EdgeInsets.only(top: 7),
child: RichText(
text: TextSpan(
text: "${S.current.voting_weight}: ${rep.weight.toString()}%",
style: TextStyle(
color:
Theme.of(context).extension<CakeTextTheme>()!.secondaryTextColor,
fontWeight: FontWeight.w700,
fontSize: 14.0,
),
),
),
),
Container(
margin: const EdgeInsets.only(top: 4),
child: RichText(
text: TextSpan(
text: '',
children: [
TextSpan(
text: "${S.current.uptime}: ",
style: TextStyle(
color: Theme.of(context)
.extension<CakeTextTheme>()!
.secondaryTextColor,
fontWeight: FontWeight.w700,
fontSize: 14,
),
),
TextSpan(
text: rep.uptime,
style: TextStyle(
color: Theme.of(context)
.extension<CakeTextTheme>()!
.secondaryTextColor,
fontWeight: FontWeight.w900,
fontSize: 14,
),
),
],
),
),
),
],
),
),
Container(
margin: const EdgeInsetsDirectional.only(end: 24, start: 14),
child: Stack(
children: <Widget>[
Icon(
Icons.verified,
color: Theme.of(context).primaryColor,
size: 50,
),
Positioned.fill(
child: Container(
margin: EdgeInsets.all(13),
color: Theme.of(context).primaryColor,
),
),
Container(
alignment: const AlignmentDirectional(-0.03, 0.03),
width: 50,
height: 50,
child: Text(
(rep.score).toString(),
textAlign: TextAlign.center,
style: TextStyle(
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
fontSize: 13,
fontWeight: FontWeight.w800,
),
),
),
],
),
), ),
], ],
), ),
), ),
bottomSectionPadding: EdgeInsets.only(bottom: 24),
bottomSection: Observer(
builder: (_) => Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Flexible(
child: Container(
padding: EdgeInsets.only(right: 8.0),
child: LoadingPrimaryButton(
onPressed: () async {
if (_formKey.currentState != null &&
!_formKey.currentState!.validate()) {
return;
}
final confirmed = await showPopUp<bool>(
context: context,
builder: (BuildContext context) {
return AlertWithTwoActions(
alertTitle: S.of(context).change_rep,
alertContent: S.of(context).change_rep_message,
rightButtonText: S.of(context).change,
leftButtonText: S.of(context).cancel,
actionRightButton: () => Navigator.pop(context, true),
actionLeftButton: () => Navigator.pop(context, false));
}) ??
false;
if (confirmed) {
try {
_settingsStore.defaultNanoRep = _addressController.text;
await nano!.changeRep(_wallet, _addressController.text);
await showPopUp<void>(
context: context,
builder: (BuildContext context) {
return AlertWithOneAction(
alertTitle: S.of(context).successful,
alertContent: S.of(context).change_rep_successful,
buttonText: S.of(context).ok,
buttonAction: () => Navigator.pop(context));
});
} catch (e) {
await showPopUp<void>(
context: context,
builder: (BuildContext context) {
return AlertWithOneAction(
alertTitle: S.of(context).error,
alertContent: e.toString(),
buttonText: S.of(context).ok,
buttonAction: () => Navigator.pop(context));
});
throw e;
}
}
},
text: S.of(context).change,
color: Theme.of(context).primaryColor,
textColor: Colors.white,
),
)),
],
)),
), ),
), ],
); );
} }
String _sanitizeAlias(String? alias) {
if (alias != null) {
return alias.replaceAll(RegExp(r'[^a-zA-Z_.!?_;:-]'), '');
}
return '';
}
} }

View file

@ -18,6 +18,7 @@ class NodeCreateOrEditPage extends BasePage {
NodeCreateOrEditPage({required this.nodeCreateOrEditViewModel,this.editingNode, this.isSelected}) NodeCreateOrEditPage({required this.nodeCreateOrEditViewModel,this.editingNode, this.isSelected})
: _formKey = GlobalKey<FormState>(), : _formKey = GlobalKey<FormState>(),
_addressController = TextEditingController(), _addressController = TextEditingController(),
_pathController = TextEditingController(),
_portController = TextEditingController(), _portController = TextEditingController(),
_loginController = TextEditingController(), _loginController = TextEditingController(),
_passwordController = TextEditingController() { _passwordController = TextEditingController() {
@ -49,6 +50,8 @@ class NodeCreateOrEditPage extends BasePage {
_addressController.addListener( _addressController.addListener(
() => nodeCreateOrEditViewModel.address = _addressController.text); () => nodeCreateOrEditViewModel.address = _addressController.text);
_pathController.addListener(
() => nodeCreateOrEditViewModel.path = _pathController.text);
_portController.addListener( _portController.addListener(
() => nodeCreateOrEditViewModel.port = _portController.text); () => nodeCreateOrEditViewModel.port = _portController.text);
_loginController.addListener( _loginController.addListener(
@ -59,6 +62,7 @@ class NodeCreateOrEditPage extends BasePage {
final GlobalKey<FormState> _formKey; final GlobalKey<FormState> _formKey;
final TextEditingController _addressController; final TextEditingController _addressController;
final TextEditingController _pathController;
final TextEditingController _portController; final TextEditingController _portController;
final TextEditingController _loginController; final TextEditingController _loginController;
final TextEditingController _passwordController; final TextEditingController _passwordController;

View file

@ -16,13 +16,15 @@ class NodeForm extends StatelessWidget {
required this.formKey, required this.formKey,
this.editingNode, this.editingNode,
}) : _addressController = TextEditingController(text: editingNode?.uri.host.toString()), }) : _addressController = TextEditingController(text: editingNode?.uri.host.toString()),
_pathController = TextEditingController(text: editingNode?.path.toString()),
_portController = TextEditingController(text: editingNode?.uri.port.toString()), _portController = TextEditingController(text: editingNode?.uri.port.toString()),
_loginController = TextEditingController(text: editingNode?.login), _loginController = TextEditingController(text: editingNode?.login),
_passwordController = TextEditingController(text: editingNode?.password), _passwordController = TextEditingController(text: editingNode?.password),
_socksAddressController = TextEditingController(text: editingNode?.socksProxyAddress){ _socksAddressController = TextEditingController(text: editingNode?.socksProxyAddress) {
if (editingNode != null) { if (editingNode != null) {
nodeViewModel nodeViewModel
..setAddress((editingNode!.uri.host.toString())) ..setAddress((editingNode!.uri.host.toString()))
..setPath((editingNode!.path.toString()))
..setPort((editingNode!.uri.port.toString())) ..setPort((editingNode!.uri.port.toString()))
..setPassword((editingNode!.password ?? '')) ..setPassword((editingNode!.password ?? ''))
..setLogin((editingNode!.login ?? '')) ..setLogin((editingNode!.login ?? ''))
@ -57,10 +59,12 @@ class NodeForm extends StatelessWidget {
}); });
_addressController.addListener(() => nodeViewModel.address = _addressController.text); _addressController.addListener(() => nodeViewModel.address = _addressController.text);
_pathController.addListener(() => nodeViewModel.path = _pathController.text);
_portController.addListener(() => nodeViewModel.port = _portController.text); _portController.addListener(() => nodeViewModel.port = _portController.text);
_loginController.addListener(() => nodeViewModel.login = _loginController.text); _loginController.addListener(() => nodeViewModel.login = _loginController.text);
_passwordController.addListener(() => nodeViewModel.password = _passwordController.text); _passwordController.addListener(() => nodeViewModel.password = _passwordController.text);
_socksAddressController.addListener(() => nodeViewModel.socksProxyAddress = _socksAddressController.text); _socksAddressController
.addListener(() => nodeViewModel.socksProxyAddress = _socksAddressController.text);
} }
final NodeCreateOrEditViewModel nodeViewModel; final NodeCreateOrEditViewModel nodeViewModel;
@ -68,6 +72,7 @@ class NodeForm extends StatelessWidget {
final Node? editingNode; final Node? editingNode;
final TextEditingController _addressController; final TextEditingController _addressController;
final TextEditingController _pathController;
final TextEditingController _portController; final TextEditingController _portController;
final TextEditingController _loginController; final TextEditingController _loginController;
final TextEditingController _passwordController; final TextEditingController _passwordController;
@ -91,6 +96,18 @@ class NodeForm extends StatelessWidget {
], ],
), ),
SizedBox(height: 10.0), SizedBox(height: 10.0),
Row(
children: <Widget>[
Expanded(
child: BaseTextFormField(
controller: _pathController,
hintText: "/path",
validator: NodePathValidator(),
),
)
],
),
SizedBox(height: 10.0),
Row( Row(
children: <Widget>[ children: <Widget>[
Expanded( Expanded(
@ -103,6 +120,26 @@ class NodeForm extends StatelessWidget {
], ],
), ),
SizedBox(height: 10.0), SizedBox(height: 10.0),
Padding(
padding: EdgeInsets.only(top: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.max,
children: [
Observer(
builder: (_) => StandardCheckbox(
value: nodeViewModel.useSSL,
gradientBackground: true,
borderColor: Theme.of(context).dividerColor,
iconColor: Colors.white,
onChanged: (value) => nodeViewModel.useSSL = value,
caption: S.of(context).use_ssl,
),
)
],
),
),
SizedBox(height: 10.0),
if (nodeViewModel.hasAuthCredentials) ...[ if (nodeViewModel.hasAuthCredentials) ...[
Row( Row(
children: <Widget>[ children: <Widget>[
@ -123,25 +160,6 @@ class NodeForm extends StatelessWidget {
)) ))
], ],
), ),
Padding(
padding: EdgeInsets.only(top: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.max,
children: [
Observer(
builder: (_) => StandardCheckbox(
value: nodeViewModel.useSSL,
gradientBackground: true,
borderColor: Theme.of(context).dividerColor,
iconColor: Colors.white,
onChanged: (value) => nodeViewModel.useSSL = value,
caption: S.of(context).use_ssl,
),
)
],
),
),
Padding( Padding(
padding: EdgeInsets.only(top: 20), padding: EdgeInsets.only(top: 20),
child: Row( child: Row(
@ -163,44 +181,44 @@ class NodeForm extends StatelessWidget {
), ),
Observer( Observer(
builder: (_) => Column( builder: (_) => Column(
children: [ children: [
Padding( Padding(
padding: EdgeInsets.only(top: 20), padding: EdgeInsets.only(top: 20),
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.max, mainAxisSize: MainAxisSize.max,
children: [ children: [
StandardCheckbox( StandardCheckbox(
value: nodeViewModel.useSocksProxy, value: nodeViewModel.useSocksProxy,
gradientBackground: true, gradientBackground: true,
borderColor: Theme.of(context).dividerColor, borderColor: Theme.of(context).dividerColor,
iconColor: Colors.white, iconColor: Colors.white,
onChanged: (value) { onChanged: (value) {
if (!value) { if (!value) {
_socksAddressController.text = ''; _socksAddressController.text = '';
} }
nodeViewModel.useSocksProxy = value; nodeViewModel.useSocksProxy = value;
}, },
caption: 'SOCKS Proxy', caption: 'SOCKS Proxy',
), ),
], ],
), ),
), ),
if (nodeViewModel.useSocksProxy) ...[ if (nodeViewModel.useSocksProxy) ...[
SizedBox(height: 10.0), SizedBox(height: 10.0),
Row( Row(
children: <Widget>[ children: <Widget>[
Expanded( Expanded(
child: BaseTextFormField( child: BaseTextFormField(
controller: _socksAddressController, controller: _socksAddressController,
hintText: '[<ip>:]<port>', hintText: '[<ip>:]<port>',
validator: SocksProxyNodeAddressValidator(), validator: SocksProxyNodeAddressValidator(),
)) ))
], ],
), ),
] ]
], ],
)), )),
] ]
], ],
), ),

View file

@ -99,12 +99,7 @@ class ReceivePage extends BasePage {
@override @override
Widget body(BuildContext context) { Widget body(BuildContext context) {
final isElectrumWallet = addressListViewModel.isElectrumWallet; return KeyboardActions(
return (addressListViewModel.type == WalletType.monero ||
addressListViewModel.type == WalletType.haven ||
addressListViewModel.type == WalletType.nano ||
isElectrumWallet)
? KeyboardActions(
config: KeyboardActionsConfig( config: KeyboardActionsConfig(
keyboardActionsPlatform: KeyboardActionsPlatform.IOS, keyboardActionsPlatform: KeyboardActionsPlatform.IOS,
keyboardBarColor: Theme.of(context).extension<KeyboardTheme>()!.keyboardBarColor, keyboardBarColor: Theme.of(context).extension<KeyboardTheme>()!.keyboardBarColor,
@ -213,32 +208,6 @@ class ReceivePage extends BasePage {
})), })),
], ],
), ),
)) ));
: Padding(
padding: EdgeInsets.fromLTRB(24, 24, 24, 32),
child: Column(
children: [
Expanded(
flex: 7,
child: QRWidget(
formKey: _formKey,
heroTag: _heroTag,
addressListViewModel: addressListViewModel,
amountTextFieldFocusNode: _cryptoAmountFocus,
amountController: _amountController,
isLight: currentTheme.type == ThemeType.light),
),
Expanded(
flex: 2,
child: SizedBox(),
),
Text(S.of(context).electrum_address_disclaimer,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 15,
color: Theme.of(context).extension<BalancePageTheme>()!.labelTextColor)),
],
),
);
} }
} }

View file

@ -1,5 +1,6 @@
import 'package:auto_size_text/auto_size_text.dart'; import 'package:auto_size_text/auto_size_text.dart';
import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/utils/responsive_layout_util.dart';
import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_list_item.dart'; import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_list_item.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_slidable/flutter_slidable.dart'; import 'package:flutter_slidable/flutter_slidable.dart';
@ -81,41 +82,45 @@ class AddressCell extends StatelessWidget {
child: Column( child: Column(
children: [ children: [
Row( Row(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: name.isNotEmpty ? MainAxisAlignment.spaceBetween : MainAxisAlignment.center,
mainAxisSize: MainAxisSize.max, mainAxisSize: MainAxisSize.max,
children: [ children: [
if (isChange) Row(
Padding( children: [
padding: const EdgeInsets.only(right: 8.0), if (isChange)
child: Container( Padding(
height: 20, padding: const EdgeInsets.only(right: 8.0),
padding: EdgeInsets.all(4), child: Container(
decoration: BoxDecoration( height: 20,
borderRadius: BorderRadius.all(Radius.circular(8.5)), padding: EdgeInsets.all(4),
color: textColor), decoration: BoxDecoration(
alignment: Alignment.center, borderRadius: BorderRadius.all(Radius.circular(8.5)),
child: Text( color: textColor),
S.of(context).unspent_change, alignment: Alignment.center,
style: TextStyle( child: Text(
color: backgroundColor, S.of(context).unspent_change,
fontSize: 10, style: TextStyle(
fontWeight: FontWeight.w600, color: backgroundColor,
fontSize: 10,
fontWeight: FontWeight.w600,
),
),
), ),
), ),
), if (name.isNotEmpty)
), Text(
if (name.isNotEmpty) '$name',
Text( style: TextStyle(
'$name - ', fontSize: 14,
style: TextStyle( fontWeight: FontWeight.w600,
fontSize: 14, color: textColor,
fontWeight: FontWeight.w600, ),
color: textColor, ),
), ],
), ),
Flexible( Flexible(
child: AutoSizeText( child: AutoSizeText(
formattedAddress, responsiveLayoutUtil.shouldRenderTabletUI ? address : formattedAddress,
maxLines: 1, maxLines: 1,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
style: TextStyle( style: TextStyle(

View file

@ -100,7 +100,10 @@ class SendPage extends BasePage {
AppBarStyle get appBarStyle => AppBarStyle.transparent; AppBarStyle get appBarStyle => AppBarStyle.transparent;
double _sendCardHeight(BuildContext context) { double _sendCardHeight(BuildContext context) {
final double initialHeight = sendViewModel.hasCoinControl ? 500 : 465; double initialHeight = 450;
if (sendViewModel.hasCoinControl) {
initialHeight += 35;
}
if (!responsiveLayoutUtil.shouldRenderMobileUI) { if (!responsiveLayoutUtil.shouldRenderMobileUI) {
return initialHeight - 66; return initialHeight - 66;
@ -190,7 +193,7 @@ class SendPage extends BasePage {
}, },
)), )),
Padding( Padding(
padding: EdgeInsets.only(top: 10, left: 24, right: 24, bottom: 10), padding: EdgeInsets.only(left: 24, right: 24, bottom: 10),
child: Container( child: Container(
height: 10, height: 10,
child: Observer( child: Observer(
@ -456,7 +459,7 @@ class SendPage extends BasePage {
? '. ${S.of(_dialogContext).waitFewSecondForTxUpdate}' : ''; ? '. ${S.of(_dialogContext).waitFewSecondForTxUpdate}' : '';
final newContactMessage = newContactAddress != null final newContactMessage = newContactAddress != null
? '\n${S.of(context).add_contact_to_address_book}' : ''; ? '\n${S.of(_dialogContext).add_contact_to_address_book}' : '';
final alertContent = final alertContent =
"$successMessage$waitMessage$newContactMessage"; "$successMessage$waitMessage$newContactMessage";

View file

@ -1,16 +1,17 @@
import 'package:cake_wallet/themes/extensions/keyboard_theme.dart';
import 'package:cake_wallet/entities/priority_for_wallet_type.dart'; import 'package:cake_wallet/entities/priority_for_wallet_type.dart';
import 'package:cake_wallet/src/widgets/picker.dart';
import 'package:cake_wallet/themes/extensions/keyboard_theme.dart';
import 'package:cake_wallet/src/screens/exchange/widgets/currency_picker.dart'; import 'package:cake_wallet/src/screens/exchange/widgets/currency_picker.dart';
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart'; import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
import 'package:cake_wallet/utils/payment_request.dart'; import 'package:cake_wallet/utils/payment_request.dart';
import 'package:cake_wallet/utils/responsive_layout_util.dart'; import 'package:cake_wallet/utils/responsive_layout_util.dart';
import 'package:cw_core/crypto_currency.dart'; import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/currency.dart'; import 'package:cw_core/currency.dart';
import 'package:cw_core/transaction_priority.dart';
import 'package:cake_wallet/routes.dart'; import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/src/widgets/keyboard_done_button.dart'; import 'package:cake_wallet/src/widgets/keyboard_done_button.dart';
import 'package:cake_wallet/src/widgets/picker.dart';
import 'package:cake_wallet/view_model/send/output.dart'; import 'package:cake_wallet/view_model/send/output.dart';
import 'package:cw_core/transaction_priority.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:flutter_mobx/flutter_mobx.dart';
@ -456,7 +457,7 @@ class SendCardState extends State<SendCard> with AutomaticKeepAliveClientMixin<S
Observer( Observer(
builder: (_) => GestureDetector( builder: (_) => GestureDetector(
onTap: sendViewModel.hasFeesPriority onTap: sendViewModel.hasFeesPriority
? () => _setTransactionPriority(context) ? () => pickTransactionPriority(context)
: () {}, : () {},
child: Container( child: Container(
padding: EdgeInsets.only(top: 24), padding: EdgeInsets.only(top: 24),
@ -669,22 +670,41 @@ class SendCardState extends State<SendCard> with AutomaticKeepAliveClientMixin<S
_effectsInstalled = true; _effectsInstalled = true;
} }
Future<void> _setTransactionPriority(BuildContext context) async { Future<void> pickTransactionPriority(BuildContext context) async {
final items = priorityForWalletType(sendViewModel.walletType); final items = priorityForWalletType(sendViewModel.walletType);
final selectedItem = items.indexOf(sendViewModel.transactionPriority); final selectedItem = items.indexOf(sendViewModel.transactionPriority);
final customItemIndex = sendViewModel.getCustomPriorityIndex(items);
final isBitcoinWallet = sendViewModel.walletType == WalletType.bitcoin;
double? customFeeRate = isBitcoinWallet ? sendViewModel.customBitcoinFeeRate.toDouble() : null;
await showPopUp<void>( await showPopUp<void>(
context: context, context: context,
builder: (_) => Picker( builder: (BuildContext context) {
items: items, int selectedIdx = selectedItem;
displayItem: sendViewModel.displayFeeRate, return StatefulBuilder(
selectedAtIndex: selectedItem, builder: (BuildContext context, StateSetter setState) {
title: S.of(context).please_select, return Picker(
mainAxisAlignment: MainAxisAlignment.center, items: items,
onItemSelected: (TransactionPriority priority) => displayItem: (TransactionPriority priority) =>
sendViewModel.setTransactionPriority(priority), sendViewModel.displayFeeRate(priority, customFeeRate?.round()),
), selectedAtIndex: selectedIdx,
customItemIndex: customItemIndex,
title: S.of(context).please_select,
headerEnabled: !isBitcoinWallet,
closeOnItemSelected: !isBitcoinWallet,
mainAxisAlignment: MainAxisAlignment.center,
sliderValue: customFeeRate,
onSliderChanged: (double newValue) => setState(() => customFeeRate = newValue),
onItemSelected: (TransactionPriority priority) {
sendViewModel.setTransactionPriority(priority);
setState(() => selectedIdx = items.indexOf(priority));
},
);
},
);
},
); );
if (isBitcoinWallet) sendViewModel.customBitcoinFeeRate = customFeeRate!.round();
} }
void _presentPicker(BuildContext context) { void _presentPicker(BuildContext context) {

View file

@ -2,11 +2,12 @@ import 'package:cake_wallet/entities/priority_for_wallet_type.dart';
import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/routes.dart'; import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/src/screens/base_page.dart'; import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/src/screens/settings/widgets/setting_priority_picker_cell.dart';
import 'package:cake_wallet/src/screens/settings/widgets/settings_cell_with_arrow.dart'; import 'package:cake_wallet/src/screens/settings/widgets/settings_cell_with_arrow.dart';
import 'package:cake_wallet/src/screens/settings/widgets/settings_picker_cell.dart'; import 'package:cake_wallet/src/screens/settings/widgets/settings_picker_cell.dart';
import 'package:cake_wallet/src/screens/settings/widgets/settings_version_cell.dart'; import 'package:cake_wallet/src/screens/settings/widgets/settings_version_cell.dart';
import 'package:cake_wallet/src/widgets/standard_list.dart';
import 'package:cake_wallet/view_model/settings/other_settings_view_model.dart'; import 'package:cake_wallet/view_model/settings/other_settings_view_model.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:flutter_mobx/flutter_mobx.dart';
@ -27,13 +28,23 @@ class OtherSettingsPage extends BasePage {
child: Column( child: Column(
children: [ children: [
if (_otherSettingsViewModel.displayTransactionPriority) if (_otherSettingsViewModel.displayTransactionPriority)
SettingsPickerCell( _otherSettingsViewModel.walletType == WalletType.bitcoin ?
title: S.current.settings_fee_priority, SettingsPriorityPickerCell(
items: priorityForWalletType(_otherSettingsViewModel.walletType), title: S.current.settings_fee_priority,
displayItem: _otherSettingsViewModel.getDisplayPriority, items: priorityForWalletType(_otherSettingsViewModel.walletType),
selectedItem: _otherSettingsViewModel.transactionPriority, displayItem: _otherSettingsViewModel.getDisplayBitcoinPriority,
onItemSelected: _otherSettingsViewModel.onDisplayPrioritySelected, selectedItem: _otherSettingsViewModel.transactionPriority,
), customItemIndex: _otherSettingsViewModel.customPriorityItemIndex,
onItemSelected: _otherSettingsViewModel.onDisplayBitcoinPrioritySelected,
customValue: _otherSettingsViewModel.customBitcoinFeeRate,
) :
SettingsPickerCell(
title: S.current.settings_fee_priority,
items: priorityForWalletType(_otherSettingsViewModel.walletType),
displayItem: _otherSettingsViewModel.getDisplayPriority,
selectedItem: _otherSettingsViewModel.transactionPriority,
onItemSelected: _otherSettingsViewModel.onDisplayPrioritySelected,
),
if (_otherSettingsViewModel.changeRepresentativeEnabled) if (_otherSettingsViewModel.changeRepresentativeEnabled)
SettingsCellWithArrow( SettingsCellWithArrow(
title: S.current.change_rep, title: S.current.change_rep,

View file

@ -55,7 +55,9 @@ class PrivacyPage extends BasePage {
}), }),
if (_privacySettingsViewModel.isAutoGenerateSubaddressesVisible) if (_privacySettingsViewModel.isAutoGenerateSubaddressesVisible)
SettingsSwitcherCell( SettingsSwitcherCell(
title: S.current.auto_generate_subaddresses, title: _privacySettingsViewModel.isMoneroWallet
? S.current.auto_generate_subaddresses
: S.current.auto_generate_addresses,
value: _privacySettingsViewModel.isAutoGenerateSubaddressesEnabled, value: _privacySettingsViewModel.isAutoGenerateSubaddressesEnabled,
onValueChange: (BuildContext _, bool value) { onValueChange: (BuildContext _, bool value) {
_privacySettingsViewModel.setAutoGenerateSubaddresses(value); _privacySettingsViewModel.setAutoGenerateSubaddresses(value);

View file

@ -0,0 +1,78 @@
import 'package:cake_wallet/themes/extensions/transaction_trade_theme.dart';
import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:flutter/material.dart';
import 'package:cake_wallet/src/widgets/picker.dart';
import 'package:cake_wallet/src/widgets/standard_list.dart';
class SettingsPriorityPickerCell<ItemType> extends StandardListRow {
SettingsPriorityPickerCell(
{required String title,
required this.selectedItem,
required this.items,
this.displayItem,
this.images,
this.searchHintText,
this.isGridView = false,
this.matchingCriteria,
this.customValue,
this.customItemIndex,
this.onItemSelected})
: super(
title: title,
isSelected: false,
onTap: (BuildContext context) async {
var selectedAtIndex = items.indexOf(selectedItem);
double sliderValue = customValue ?? 0.0;
await showPopUp<void>(
context: context,
builder: (BuildContext context) {
return StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
return Picker(
items: items,
displayItem: (ItemType item) => displayItem!(item, sliderValue.round()),
selectedAtIndex: selectedAtIndex,
customItemIndex: customItemIndex,
headerEnabled: false,
closeOnItemSelected: false,
mainAxisAlignment: MainAxisAlignment.center,
sliderValue: sliderValue,
onSliderChanged: (double newValue) =>
setState(() => sliderValue = newValue),
onItemSelected: (ItemType priority) {
setState(() => selectedAtIndex = items.indexOf(priority));
onItemSelected?.call(priority, sliderValue);
},
);
},
);
},
);
onItemSelected?.call(items[selectedAtIndex], sliderValue);
});
final ItemType selectedItem;
final List<ItemType> items;
final void Function(ItemType item, double customValue)? onItemSelected;
final String Function(ItemType item, int value)? displayItem;
final List<Image>? images;
final String? searchHintText;
final bool isGridView;
final bool Function(ItemType, String)? matchingCriteria;
double? customValue;
int? customItemIndex;
@override
Widget buildTrailing(BuildContext context) {
return Text(
displayItem?.call(selectedItem,customValue?.round() ?? 0) ?? selectedItem.toString(),
textAlign: TextAlign.right,
style: TextStyle(
fontSize: 14.0,
fontWeight: FontWeight.w500,
color: Theme.of(context).extension<TransactionTradeTheme>()!.detailsTitlesColor,
),
);
}
}

View file

@ -0,0 +1,23 @@
import 'package:cake_wallet/src/screens/transaction_details/transaction_details_list_item.dart';
class StandardPickerListItem<T> extends TransactionDetailsListItem {
StandardPickerListItem(
{required String title,
required String value,
required this.items,
required this.displayItem,
required this.onSliderChanged,
required this.onItemSelected,
required this.selectedIdx,
required this.customItemIndex,
required this.customValue})
: super(title: title, value: value);
final List<T> items;
final String Function(T item, double sliderValue) displayItem;
final Function(double) onSliderChanged;
final Function(T) onItemSelected;
final int selectedIdx;
final int customItemIndex;
double customValue;
}

View file

@ -0,0 +1,199 @@
import 'package:cake_wallet/core/execution_state.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/src/screens/send/widgets/confirm_sending_alert.dart';
import 'package:cake_wallet/src/screens/transaction_details/rbf_details_list_fee_picker_item.dart';
import 'package:cake_wallet/src/screens/transaction_details/standart_list_item.dart';
import 'package:cake_wallet/src/screens/transaction_details/textfield_list_item.dart';
import 'package:cake_wallet/src/screens/transaction_details/transaction_expandable_list_item.dart';
import 'package:cake_wallet/src/screens/transaction_details/widgets/textfield_list_row.dart';
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
import 'package:cake_wallet/src/widgets/list_row.dart';
import 'package:cake_wallet/src/widgets/primary_button.dart';
import 'package:cake_wallet/src/widgets/standard_expandable_list.dart';
import 'package:cake_wallet/src/widgets/standard_list.dart';
import 'package:cake_wallet/src/widgets/standard_picker_list.dart';
import 'package:cake_wallet/utils/show_bar.dart';
import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:cake_wallet/view_model/send/send_view_model_state.dart';
import 'package:cake_wallet/view_model/transaction_details_view_model.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:mobx/mobx.dart';
class RBFDetailsPage extends BasePage {
RBFDetailsPage({required this.transactionDetailsViewModel});
@override
String get title => S.current.bump_fee;
final TransactionDetailsViewModel transactionDetailsViewModel;
bool _effectsInstalled = false;
@override
Widget body(BuildContext context) {
_setEffects(context);
return Column(
children: [
Expanded(
child: SectionStandardList(
sectionCount: 1,
itemCounter: (int _) => transactionDetailsViewModel.RBFListItems.length,
itemBuilder: (__, index) {
final item = transactionDetailsViewModel.RBFListItems[index];
if (item is StandartListItem) {
return GestureDetector(
onTap: () {
Clipboard.setData(ClipboardData(text: item.value));
showBar<void>(context, S.of(context).transaction_details_copied(item.title));
},
child: ListRow(title: '${item.title}:', value: item.value),
);
}
if (item is StandardExpandableListItem) {
return StandardExpandableList(
title: '${item.title}: ${item.expandableItems.length}',
expandableItems: item.expandableItems,
);
}
if (item is StandardPickerListItem) {
return StandardPickerList(
title: item.title,
value: item.value,
items: item.items,
displayItem: item.displayItem,
onSliderChanged: item.onSliderChanged,
onItemSelected: item.onItemSelected,
selectedIdx: item.selectedIdx,
customItemIndex: item.customItemIndex,
customValue: item.customValue,
);
}
if (item is TextFieldListItem) {
return TextFieldListRow(
title: item.title,
value: item.value,
onSubmitted: item.onSubmitted,
);
}
return Container();
}),
),
Padding(
padding: const EdgeInsets.all(24),
child: Observer(
builder: (_) => LoadingPrimaryButton(
onPressed: () async {
transactionDetailsViewModel
.replaceByFee(transactionDetailsViewModel.newFee.toString());
},
text: S.of(context).send,
isLoading:
transactionDetailsViewModel.sendViewModel.state is IsExecutingState,
color: Theme.of(context).primaryColor,
textColor: Colors.white,
))),
],
);
}
void _setEffects(BuildContext context) {
if (_effectsInstalled) {
return;
}
reaction((_) => transactionDetailsViewModel.sendViewModel.state, (ExecutionState state) {
if (state is FailureState) {
WidgetsBinding.instance.addPostFrameCallback((_) {
showPopUp<void>(
context: context,
builder: (BuildContext popupContext) {
return AlertWithOneAction(
alertTitle: S.of(popupContext).error,
alertContent: state.error,
buttonText: S.of(popupContext).ok,
buttonAction: () => Navigator.of(popupContext).pop());
});
});
}
if (state is AwaitingConfirmationState) {
WidgetsBinding.instance.addPostFrameCallback((_) {
showPopUp<void>(
context: context,
builder: (BuildContext popupContext) {
return AlertWithTwoActions(
alertTitle: state.title ?? '',
alertContent: state.message ?? '',
rightButtonText: S.of(context).ok,
leftButtonText: S.of(context).cancel,
actionRightButton: () {
state.onConfirm?.call();
Navigator.of(popupContext).pop();
},
actionLeftButton: () {
state.onCancel?.call();
Navigator.of(popupContext).pop();
});
});
});
}
if (state is ExecutedSuccessfullyState) {
WidgetsBinding.instance.addPostFrameCallback((_) {
showPopUp<void>(
context: context,
builder: (BuildContext popupContext) {
return ConfirmSendingAlert(
alertTitle: S.of(popupContext).confirm_sending,
amount: S.of(popupContext).send_amount,
amountValue: transactionDetailsViewModel
.sendViewModel.pendingTransaction!.amountFormatted,
fee: S.of(popupContext).send_fee,
feeValue:
transactionDetailsViewModel.sendViewModel.pendingTransaction!.feeFormatted,
rightButtonText: S.of(popupContext).send,
leftButtonText: S.of(popupContext).cancel,
actionRightButton: () async {
Navigator.of(popupContext).pop();
await transactionDetailsViewModel.sendViewModel.commitTransaction();
// transactionStatePopup();
},
actionLeftButton: () => Navigator.of(popupContext).pop(),
feeFiatAmount:
transactionDetailsViewModel.pendingTransactionFeeFiatAmountFormatted,
fiatAmountValue:
transactionDetailsViewModel.pendingTransactionFiatAmountValueFormatted,
outputs: transactionDetailsViewModel.sendViewModel.outputs);
});
});
}
if (state is TransactionCommitted) {
WidgetsBinding.instance.addPostFrameCallback((_) {
if (context.mounted) {
showPopUp<void>(
context: context,
builder: (BuildContext popupContext) {
return AlertWithOneAction(
alertTitle: S.of(popupContext).sending,
alertContent: S.of(popupContext).transaction_sent,
buttonText: S.of(popupContext).ok,
buttonAction: () => Navigator.of(popupContext).pop());
});
}
});
}
});
_effectsInstalled = true;
}
}

View file

@ -1,15 +1,18 @@
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/src/screens/new_wallet/widgets/select_button.dart';
import 'package:cake_wallet/src/screens/transaction_details/blockexplorer_list_item.dart';
import 'package:cake_wallet/src/screens/transaction_details/standart_list_item.dart';
import 'package:cake_wallet/src/screens/transaction_details/textfield_list_item.dart'; import 'package:cake_wallet/src/screens/transaction_details/textfield_list_item.dart';
import 'package:cake_wallet/src/screens/transaction_details/widgets/textfield_list_row.dart'; import 'package:cake_wallet/src/screens/transaction_details/widgets/textfield_list_row.dart';
import 'package:cake_wallet/src/widgets/list_row.dart';
import 'package:cake_wallet/src/widgets/standard_list.dart'; import 'package:cake_wallet/src/widgets/standard_list.dart';
import 'package:cake_wallet/utils/show_bar.dart'; import 'package:cake_wallet/utils/show_bar.dart';
import 'package:cake_wallet/view_model/transaction_details_view_model.dart'; import 'package:cake_wallet/view_model/transaction_details_view_model.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:cake_wallet/generated/i18n.dart'; import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:cake_wallet/src/widgets/list_row.dart';
import 'package:cake_wallet/src/screens/transaction_details/blockexplorer_list_item.dart';
import 'package:cake_wallet/src/screens/transaction_details/standart_list_item.dart';
import 'package:cake_wallet/src/screens/base_page.dart';
class TransactionDetailsPage extends BasePage { class TransactionDetailsPage extends BasePage {
TransactionDetailsPage({required this.transactionDetailsViewModel}); TransactionDetailsPage({required this.transactionDetailsViewModel});
@ -21,41 +24,62 @@ class TransactionDetailsPage extends BasePage {
@override @override
Widget body(BuildContext context) { Widget body(BuildContext context) {
return SectionStandardList( return Column(
sectionCount: 1, children: [
itemCounter: (int _) => transactionDetailsViewModel.items.length, Expanded(
itemBuilder: (__, index) { child: SectionStandardList(
final item = transactionDetailsViewModel.items[index]; sectionCount: 1,
itemCounter: (int _) => transactionDetailsViewModel.items.length,
itemBuilder: (__, index) {
final item = transactionDetailsViewModel.items[index];
if (item is StandartListItem) { if (item is StandartListItem) {
return GestureDetector( return GestureDetector(
onTap: () { onTap: () {
Clipboard.setData(ClipboardData(text: item.value)); Clipboard.setData(ClipboardData(text: item.value));
showBar<void>(context, showBar<void>(context, S.of(context).transaction_details_copied(item.title));
S.of(context).transaction_details_copied(item.title)); },
}, child: ListRow(title: '${item.title}:', value: item.value),
child: );
ListRow(title: '${item.title}:', value: item.value), }
);
}
if (item is BlockExplorerListItem) { if (item is BlockExplorerListItem) {
return GestureDetector( return GestureDetector(
onTap: item.onTap, onTap: item.onTap,
child: child: ListRow(title: '${item.title}:', value: item.value),
ListRow(title: '${item.title}:', value: item.value), );
); }
}
if (item is TextFieldListItem) { if (item is TextFieldListItem) {
return TextFieldListRow( return TextFieldListRow(
title: item.title, title: item.title,
value: item.value, value: item.value,
onSubmitted: item.onSubmitted, onSubmitted: item.onSubmitted,
); );
} }
return Container(); return Container();
}); }),
),
Observer(
builder: (_) {
if (transactionDetailsViewModel.canReplaceByFee) {
return Padding(
padding: const EdgeInsets.all(24),
child: SelectButton(
text: S.of(context).bump_fee,
onTap: () async {
Navigator.of(context).pushNamed(Routes.bumpFeePage,
arguments: transactionDetailsViewModel.transactionInfo);
},
),
);
}
return const SizedBox();
},
),
],
);
} }
} }

View file

@ -0,0 +1,7 @@
import 'package:cake_wallet/src/screens/transaction_details/transaction_details_list_item.dart';
class StandardExpandableListItem<T> extends TransactionDetailsListItem {
StandardExpandableListItem({required String title, required this.expandableItems})
: super(title: title, value: '');
final List<T> expandableItems;
}

View file

@ -30,7 +30,7 @@ class PairingItemWidget extends StatelessWidget {
leading: CakeImageWidget( leading: CakeImageWidget(
imageUrl: metadata.icons.isNotEmpty ? metadata.icons[0]: null, imageUrl: metadata.icons.isNotEmpty ? metadata.icons[0]: null,
displayOnError: CircleAvatar( displayOnError: CircleAvatar(
backgroundImage: AssetImage('assets/images/default_icon.png'), backgroundImage: AssetImage('assets/images/walletconnect_logo.png'),
), ),
), ),
title: Text( title: Text(

View file

@ -18,7 +18,7 @@ class CakeImageWidget extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
try { try {
if (imageUrl == null) return _displayOnError!; if (imageUrl == null || imageUrl!.isEmpty) return _displayOnError!;
if (imageUrl!.contains('assets/images')) { if (imageUrl!.contains('assets/images')) {
return Image.asset( return Image.asset(

View file

@ -31,7 +31,6 @@ class CheckboxWidgetState extends State<CheckboxWidget> {
}, },
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[ children: <Widget>[
Container( Container(
height: 24.0, height: 24.0,

View file

@ -4,15 +4,15 @@ import 'package:flutter/material.dart';
import 'package:cake_wallet/themes/extensions/dashboard_page_theme.dart'; import 'package:cake_wallet/themes/extensions/dashboard_page_theme.dart';
class DashBoardRoundedCardWidget extends StatelessWidget { class DashBoardRoundedCardWidget extends StatelessWidget {
DashBoardRoundedCardWidget({ DashBoardRoundedCardWidget({
required this.onTap, required this.onTap,
required this.title, required this.title,
required this.subTitle, required this.subTitle,
this.onClose,
}); });
final VoidCallback onTap; final VoidCallback onTap;
final VoidCallback? onClose;
final String title; final String title;
final String subTitle; final String subTitle;
@ -26,7 +26,7 @@ class DashBoardRoundedCardWidget extends StatelessWidget {
child: Stack( child: Stack(
children: [ children: [
Container( Container(
padding: EdgeInsets.all(20), padding: EdgeInsets.fromLTRB(20, 20, 40, 20),
width: double.infinity, width: double.infinity,
decoration: BoxDecoration( decoration: BoxDecoration(
color: Theme.of(context).extension<SyncIndicatorTheme>()!.syncedBackgroundColor, color: Theme.of(context).extension<SyncIndicatorTheme>()!.syncedBackgroundColor,
@ -35,32 +35,40 @@ class DashBoardRoundedCardWidget extends StatelessWidget {
color: Theme.of(context).extension<BalancePageTheme>()!.cardBorderColor, color: Theme.of(context).extension<BalancePageTheme>()!.cardBorderColor,
), ),
), ),
child: child: Column(
Column( crossAxisAlignment: CrossAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start, children: [
children: [ Text(
Text( title,
title, style: TextStyle(
style: TextStyle( color: Theme.of(context).extension<DashboardPageTheme>()!.cardTextColor,
color: Theme.of(context).extension<DashboardPageTheme>()!.cardTextColor, fontSize: 24,
fontSize: 24, fontWeight: FontWeight.w900,
fontWeight: FontWeight.w900, ),
),
),
SizedBox(height: 5),
Text(
subTitle,
style: TextStyle(
color: Theme.of(context).extension<DashboardPageTheme>()!.cardTextColor,
fontWeight: FontWeight.w500,
fontFamily: 'Lato'),
)
],
), ),
SizedBox(height: 5),
Text(
subTitle,
style: TextStyle(
color: Theme.of(context).extension<DashboardPageTheme>()!.cardTextColor,
fontWeight: FontWeight.w500,
fontFamily: 'Lato'),
)
],
),
), ),
if (onClose != null)
Positioned(
top: 10,
right: 10,
child: IconButton(
icon: Icon(Icons.close),
onPressed: onClose,
color: Theme.of(context).extension<DashboardPageTheme>()!.cardTextColor,
),
),
], ],
), ),
); );
} }
} }

View file

@ -24,6 +24,13 @@ class Picker<Item> extends StatefulWidget {
this.isGridView = false, this.isGridView = false,
this.isSeparated = true, this.isSeparated = true,
this.hintText, this.hintText,
this.headerEnabled = true,
this.closeOnItemSelected = true,
this.sliderValue,
this.customItemIndex,
this.isWrapped = true,
this.borderColor,
this.onSliderChanged,
this.matchingCriteria, this.matchingCriteria,
}) : assert(hintText == null || }) : assert(hintText == null ||
matchingCriteria != matchingCriteria !=
@ -40,6 +47,13 @@ class Picker<Item> extends StatefulWidget {
final bool isGridView; final bool isGridView;
final bool isSeparated; final bool isSeparated;
final String? hintText; final String? hintText;
final bool headerEnabled;
final bool closeOnItemSelected;
final double? sliderValue;
final int? customItemIndex;
final bool isWrapped;
final Color? borderColor;
final Function(double)? onSliderChanged;
final bool Function(Item, String)? matchingCriteria; final bool Function(Item, String)? matchingCriteria;
@override @override
@ -124,8 +138,7 @@ class _PickerState<Item> extends State<Picker<Item>> {
containerHeight = height * 0.75; containerHeight = height * 0.75;
} }
return PickerWrapperWidget( final content = Column (
hasTitle: widget.title?.isNotEmpty ?? false,
children: [ children: [
if (widget.title?.isNotEmpty ?? false) if (widget.title?.isNotEmpty ?? false)
Container( Container(
@ -144,61 +157,71 @@ class _PickerState<Item> extends State<Picker<Item>> {
), ),
Padding( Padding(
padding: EdgeInsets.symmetric(horizontal: padding), padding: EdgeInsets.symmetric(horizontal: padding),
child: ClipRRect( child: Container(
borderRadius: BorderRadius.all(Radius.circular(30)), decoration: BoxDecoration(
child: Container( borderRadius: BorderRadius.circular(30),
color: Theme.of(context).dialogTheme.backgroundColor, border: Border.all(
child: ConstrainedBox( color: widget.borderColor ?? Colors.transparent,
constraints: BoxConstraints( ),
maxHeight: containerHeight, ),
maxWidth: ResponsiveLayoutUtilBase.kPopupWidth, child: ClipRRect(
), borderRadius: BorderRadius.all(Radius.circular(30)),
child: Column( child: Container(
mainAxisSize: MainAxisSize.min, color: Theme.of(context).dialogTheme.backgroundColor,
children: [ child: ConstrainedBox(
if (widget.hintText != null) constraints: BoxConstraints(
Padding( maxHeight: containerHeight,
padding: const EdgeInsets.all(16), maxWidth: ResponsiveLayoutUtilBase.kPopupWidth,
child: SearchBarWidget(searchController: searchController), ),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
if (widget.hintText != null)
Padding(
padding: const EdgeInsets.all(16),
child: SearchBarWidget(
searchController: searchController, hintText: widget.hintText),
),
Divider(
color: Theme.of(context).extension<PickerTheme>()!.dividerColor,
height: 1,
), ),
Divider( if (widget.selectedAtIndex != -1 && widget.headerEnabled)
color: Theme.of(context).extension<PickerTheme>()!.dividerColor, buildSelectedItem(widget.selectedAtIndex),
height: 1, Flexible(
), child: Stack(
if (widget.selectedAtIndex != -1) buildSelectedItem(widget.selectedAtIndex), alignment: Alignment.center,
Flexible( children: <Widget>[
child: Stack( filteredItems.length > 3
alignment: Alignment.center, ? Scrollbar(
children: <Widget>[ controller: controller,
filteredItems.length > 3 child: itemsList(),
? Scrollbar( )
controller: controller, : itemsList(),
child: itemsList(), (widget.description?.isNotEmpty ?? false)
) ? Positioned(
: itemsList(), bottom: padding,
(widget.description?.isNotEmpty ?? false) left: padding,
? Positioned( right: padding,
bottom: padding, child: Text(
left: padding, widget.description!,
right: padding, textAlign: TextAlign.center,
child: Text( style: TextStyle(
widget.description!, fontSize: 12,
textAlign: TextAlign.center, fontWeight: FontWeight.w500,
style: TextStyle( fontFamily: 'Lato',
fontSize: 12, decoration: TextDecoration.none,
fontWeight: FontWeight.w500, color:
fontFamily: 'Lato', Theme.of(context).extension<CakeTextTheme>()!.titleColor,
decoration: TextDecoration.none, ),
color:
Theme.of(context).extension<CakeTextTheme>()!.titleColor,
), ),
), )
) : Offstage(),
: Offstage(), ],
], ),
), ),
), ],
], ),
), ),
), ),
), ),
@ -206,9 +229,23 @@ class _PickerState<Item> extends State<Picker<Item>> {
) )
], ],
); );
if (widget.isWrapped) {
return PickerWrapperWidget(
hasTitle: widget.title?.isNotEmpty ?? false,
children: [content],
);
} else {
return content;
}
} }
Widget itemsList() { Widget itemsList() {
final itemCount = !widget.headerEnabled
? items.length
: filteredItems.isEmpty
? 0
: filteredItems.length;
return Container( return Container(
color: Theme.of(context).extension<PickerTheme>()!.dividerColor, color: Theme.of(context).extension<PickerTheme>()!.dividerColor,
child: widget.isGridView child: widget.isGridView
@ -216,13 +253,16 @@ class _PickerState<Item> extends State<Picker<Item>> {
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
controller: controller, controller: controller,
shrinkWrap: true, shrinkWrap: true,
itemCount: filteredItems.isEmpty ? 0 : filteredItems.length, itemCount: itemCount,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2, crossAxisCount: 2,
crossAxisSpacing: 2, crossAxisSpacing: 2,
childAspectRatio: 3, childAspectRatio: 3,
), ),
itemBuilder: (context, index) => buildItem(index), itemBuilder: (context, index) =>
!widget.headerEnabled && widget.selectedAtIndex == index
? buildSelectedItem(index)
: buildItem(index),
) )
: ListView.separated( : ListView.separated(
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
@ -234,83 +274,97 @@ class _PickerState<Item> extends State<Picker<Item>> {
height: 1, height: 1,
) )
: const SizedBox(), : const SizedBox(),
itemCount: filteredItems.isEmpty ? 0 : filteredItems.length, itemCount: itemCount,
itemBuilder: (context, index) => buildItem(index), itemBuilder: (context, index) =>
!widget.headerEnabled && widget.selectedAtIndex == index
? buildSelectedItem(index)
: buildItem(index),
), ),
); );
} }
Widget buildItem(int index) { Widget buildItem(int index) {
final item = filteredItems[index]; final item = widget.headerEnabled ? filteredItems[index] : items[index];
final tag = item is Currency ? item.tag : null; final tag = item is Currency ? item.tag : null;
final icon = _getItemIcon(item); final icon = _getItemIcon(item);
final image = images.isNotEmpty ? filteredImages[index] : icon; final image = images.isNotEmpty ? filteredImages[index] : icon;
final isCustomItem = widget.customItemIndex != null && index == widget.customItemIndex;
final itemContent = Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: widget.mainAxisAlignment,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
image ?? Offstage(),
Expanded(
child: Padding(
padding: EdgeInsets.only(left: image != null ? 12 : 0),
child: Row(
children: [
Flexible(
child: Text(
widget.displayItem?.call(item) ?? item.toString(),
softWrap: true,
style: TextStyle(
fontSize: 14,
fontFamily: 'Lato',
fontWeight: FontWeight.w600,
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
decoration: TextDecoration.none,
),
),
),
if (tag != null)
Align(
alignment: Alignment.topCenter,
child: Container(
width: 35.0,
height: 18.0,
child: Center(
child: Text(
tag,
style: TextStyle(
fontSize: 7.0,
fontFamily: 'Lato',
color: Theme.of(context).extension<CakeScrollbarTheme>()!.thumbColor,
),
),
),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(6.0),
//border: Border.all(color: ),
color: Theme.of(context).extension<CakeScrollbarTheme>()!.trackColor,
),
),
),
],
),
),
),
],
);
return GestureDetector( return GestureDetector(
onTap: () { onTap: () {
Navigator.of(context).pop(); if (widget.closeOnItemSelected) Navigator.of(context).pop();
onItemSelected(item!); onItemSelected(item!);
}, },
child: Container( child: Container(
height: 55, height: isCustomItem ? 95 : 55,
color: Theme.of(context).dialogTheme.backgroundColor, color: Theme.of(context).dialogTheme.backgroundColor,
padding: EdgeInsets.symmetric(horizontal: 24), padding: EdgeInsets.symmetric(horizontal: 24),
child: Row( child: isCustomItem
mainAxisSize: MainAxisSize.max, ? Column(
mainAxisAlignment: widget.mainAxisAlignment, mainAxisAlignment: MainAxisAlignment.spaceAround,
crossAxisAlignment: CrossAxisAlignment.center, children: [
children: <Widget>[ itemContent,
image ?? Offstage(), buildSlider(index: index, isActivated: widget.selectedAtIndex == index)
Expanded( ],
child: Padding( )
padding: EdgeInsets.only(left: image != null ? 12 : 0), : itemContent,
child: Row(
children: [
Flexible(
child: Text(
widget.displayItem?.call(item) ?? item.toString(),
softWrap: true,
style: TextStyle(
fontSize: 14,
fontFamily: 'Lato',
fontWeight: FontWeight.w600,
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
decoration: TextDecoration.none,
),
),
),
if (tag != null)
Align(
alignment: Alignment.topCenter,
child: Container(
width: 35.0,
height: 18.0,
child: Center(
child: Text(
tag,
style: TextStyle(
fontSize: 7.0,
fontFamily: 'Lato',
color:
Theme.of(context).extension<CakeScrollbarTheme>()!.thumbColor,
),
),
),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(6.0),
//border: Border.all(color: ),
color: Theme.of(context).extension<CakeScrollbarTheme>()!.trackColor,
),
),
),
],
),
),
),
],
),
), ),
); );
} }
@ -323,69 +377,80 @@ class _PickerState<Item> extends State<Picker<Item>> {
final image = images.isNotEmpty ? images[index] : icon; final image = images.isNotEmpty ? images[index] : icon;
return GestureDetector( final isCustomItem = widget.customItemIndex != null && index == widget.customItemIndex;
onTap: () {
Navigator.of(context).pop(); final itemContent = Row(
}, mainAxisSize: MainAxisSize.max,
child: Container( mainAxisAlignment: widget.mainAxisAlignment,
height: 55, crossAxisAlignment: CrossAxisAlignment.center,
color: Theme.of(context).dialogTheme.backgroundColor, children: <Widget>[
padding: EdgeInsets.symmetric(horizontal: 24), image ?? Offstage(),
child: Row( Expanded(
mainAxisSize: MainAxisSize.max, child: Padding(
mainAxisAlignment: widget.mainAxisAlignment, padding: EdgeInsets.only(left: image != null ? 12 : 0),
crossAxisAlignment: CrossAxisAlignment.center, child: Row(
children: <Widget>[ children: [
image ?? Offstage(), Flexible(
Expanded( child: Text(
child: Padding( widget.displayItem?.call(item) ?? item.toString(),
padding: EdgeInsets.only(left: image != null ? 12 : 0), softWrap: true,
child: Row( style: TextStyle(
children: [ fontSize: 16,
Flexible( fontFamily: 'Lato',
child: Text( fontWeight: FontWeight.w700,
widget.displayItem?.call(item) ?? item.toString(), color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
softWrap: true, decoration: TextDecoration.none,
style: TextStyle( ),
fontSize: 16, ),
fontFamily: 'Lato', ),
fontWeight: FontWeight.w700, if (tag != null)
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor, Align(
decoration: TextDecoration.none, alignment: Alignment.topCenter,
child: Container(
width: 35.0,
height: 18.0,
child: Center(
child: Text(
tag,
style: TextStyle(
fontSize: 7.0,
fontFamily: 'Lato',
color: Theme.of(context).extension<CakeScrollbarTheme>()!.thumbColor,
),
), ),
), ),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(6.0),
//border: Border.all(color: ),
color: Theme.of(context).extension<CakeScrollbarTheme>()!.trackColor,
),
), ),
if (tag != null) ),
Align( ],
alignment: Alignment.topCenter,
child: Container(
width: 35.0,
height: 18.0,
child: Center(
child: Text(
tag,
style: TextStyle(
fontSize: 7.0,
fontFamily: 'Lato',
color:
Theme.of(context).extension<CakeScrollbarTheme>()!.thumbColor,
),
),
),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(6.0),
//border: Border.all(color: ),
color: Theme.of(context).extension<CakeScrollbarTheme>()!.trackColor,
),
),
),
],
),
),
), ),
Icon(Icons.check_circle, color: Theme.of(context).primaryColor), ),
],
), ),
Icon(Icons.check_circle, color: Theme.of(context).primaryColor),
],
);
return GestureDetector(
onTap: () {
if (widget.closeOnItemSelected) Navigator.of(context).pop();
},
child: Container(
height: isCustomItem ? 95 : 55,
color: Theme.of(context).dialogTheme.backgroundColor,
padding: EdgeInsets.symmetric(horizontal: 24),
child: isCustomItem
? Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
itemContent,
buildSlider(index: index, isActivated: widget.selectedAtIndex == index)
],
)
: itemContent,
), ),
); );
} }
@ -418,4 +483,20 @@ class _PickerState<Item> extends State<Picker<Item>> {
return null; return null;
} }
Widget buildSlider({required int index, required bool isActivated}) {
return Row(
children: <Widget>[
Expanded(
child: Slider(
value: widget.sliderValue ?? 1,
onChanged: isActivated ? widget.onSliderChanged : null,
min: 1,
max: 100,
divisions: 100,
),
),
],
);
}
} }

View file

@ -2,16 +2,21 @@ import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class ScrollableWithBottomSection extends StatefulWidget { class ScrollableWithBottomSection extends StatefulWidget {
ScrollableWithBottomSection( ScrollableWithBottomSection({
{required this.content, required this.content,
required this.bottomSection, required this.bottomSection,
this.contentPadding, this.topSection,
this.bottomSectionPadding}); this.contentPadding,
this.bottomSectionPadding,
this.topSectionPadding,
});
final Widget content; final Widget content;
final Widget bottomSection; final Widget bottomSection;
final Widget? topSection;
final EdgeInsets? contentPadding; final EdgeInsets? contentPadding;
final EdgeInsets? bottomSectionPadding; final EdgeInsets? bottomSectionPadding;
final EdgeInsets? topSectionPadding;
@override @override
ScrollableWithBottomSectionState createState() => ScrollableWithBottomSectionState(); ScrollableWithBottomSectionState createState() => ScrollableWithBottomSectionState();
@ -22,6 +27,12 @@ class ScrollableWithBottomSectionState extends State<ScrollableWithBottomSection
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Column( return Column(
children: [ children: [
if (widget.topSection != null)
Padding(
padding: widget.topSectionPadding?.copyWith(top: 10) ??
EdgeInsets.only(top: 10, bottom: 20, right: 20, left: 20),
child: widget.topSection,
),
Expanded( Expanded(
child: SingleChildScrollView( child: SingleChildScrollView(
child: Padding( child: Padding(

View file

@ -19,7 +19,7 @@ class SearchBarWidget extends StatelessWidget {
controller: searchController, controller: searchController,
style: TextStyle(color: Theme.of(context).extension<PickerTheme>()!.searchHintColor), style: TextStyle(color: Theme.of(context).extension<PickerTheme>()!.searchHintColor),
decoration: InputDecoration( decoration: InputDecoration(
hintText: hintText ?? S.of(context).search_currency, hintText: hintText ?? S.of(context).search,
hintStyle: TextStyle(color: Theme.of(context).extension<PickerTheme>()!.searchHintColor), hintStyle: TextStyle(color: Theme.of(context).extension<PickerTheme>()!.searchHintColor),
prefixIcon: Image.asset("assets/images/search_icon.png", prefixIcon: Image.asset("assets/images/search_icon.png",
color: Theme.of(context).extension<PickerTheme>()!.searchIconColor), color: Theme.of(context).extension<PickerTheme>()!.searchIconColor),

View file

@ -0,0 +1,58 @@
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
import 'package:cake_wallet/themes/extensions/transaction_trade_theme.dart';
import 'package:flutter/material.dart';
class StandardExpandableList<T> extends StatelessWidget {
StandardExpandableList({
required this.title,
required this.expandableItems,
this.decoration,
});
final String title;
final List<T> expandableItems;
final Decoration? decoration;
@override
Widget build(BuildContext context) {
return Container(
decoration: decoration ??
BoxDecoration(
color: Theme.of(context).colorScheme.background,
),
child: Theme(
data: Theme.of(context).copyWith(dividerColor: Colors.transparent),
child: ExpansionTile(
iconColor: Theme.of(context).extension<TransactionTradeTheme>()!.detailsTitlesColor,
collapsedIconColor:
Theme.of(context).extension<TransactionTradeTheme>()!.detailsTitlesColor,
title: Text(
title,
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w500,
color: Theme.of(context).extension<TransactionTradeTheme>()!.detailsTitlesColor,
),
textAlign: TextAlign.left,
),
children: expandableItems.map((item) {
return Padding(
padding: const EdgeInsets.only(left: 16.0, bottom: 8.0),
child: Align(
alignment: Alignment.centerLeft,
child: Text(
item.toString(),
maxLines: 1,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor),
),
),
);
}).toList(),
),
),
);
}
}

View file

@ -0,0 +1,81 @@
import 'package:cake_wallet/src/widgets/list_row.dart';
import 'package:cake_wallet/src/widgets/picker.dart';
import 'package:cake_wallet/themes/extensions/picker_theme.dart';
import 'package:flutter/material.dart';
class StandardPickerList<T> extends StatefulWidget {
StandardPickerList({
Key? key,
required this.title,
required this.value,
required this.items,
required this.displayItem,
required this.onSliderChanged,
required this.onItemSelected,
required this.selectedIdx,
required this.customItemIndex,
required this.customValue,
}) : super(key: key);
final String title;
final List<T> items;
final int customItemIndex;
final String Function(T item, double sliderValue) displayItem;
final Function(double) onSliderChanged;
final Function(T) onItemSelected;
final String value;
final int selectedIdx;
final double customValue;
@override
_StandardPickerListState<T> createState() => _StandardPickerListState<T>();
}
class _StandardPickerListState<T> extends State<StandardPickerList<T>> {
late String value;
late int selectedIdx;
late double customValue;
@override
void initState() {
super.initState();
value = widget.value;
selectedIdx = widget.selectedIdx;
customValue = widget.customValue;
}
@override
Widget build(BuildContext context) {
String adaptedDisplayItem(T item) => widget.displayItem(item, customValue);
return Column(
children: [
ListRow(title: '${widget.title}:', value: value),
Padding(
padding: const EdgeInsets.only(left: 24, right: 24, top: 0, bottom: 24),
child: Picker(
items: widget.items,
displayItem: adaptedDisplayItem,
selectedAtIndex: selectedIdx,
customItemIndex: widget.customItemIndex,
headerEnabled: false,
closeOnItemSelected: false,
mainAxisAlignment: MainAxisAlignment.center,
sliderValue: customValue,
isWrapped: false,
borderColor: Theme.of(context).extension<PickerTheme>()!.dividerColor,
onSliderChanged: (newValue) {
setState(() => customValue = newValue);
value = widget.onSliderChanged(newValue).toString();
},
onItemSelected: (T item) {
setState(() => selectedIdx = widget.items.indexOf(item));
value = widget.onItemSelected(item).toString();
},
),
),
],
);
}
}

View file

@ -79,6 +79,7 @@ abstract class SettingsStoreBase with Store {
required Map<WalletType, Node> nodes, required Map<WalletType, Node> nodes,
required Map<WalletType, Node> powNodes, required Map<WalletType, Node> powNodes,
required this.shouldShowYatPopup, required this.shouldShowYatPopup,
required this.shouldShowRepWarning,
required this.isBitcoinBuyEnabled, required this.isBitcoinBuyEnabled,
required this.actionlistDisplayMode, required this.actionlistDisplayMode,
required this.pinTimeOutDuration, required this.pinTimeOutDuration,
@ -105,6 +106,7 @@ abstract class SettingsStoreBase with Store {
required this.lookupsUnstoppableDomains, required this.lookupsUnstoppableDomains,
required this.lookupsOpenAlias, required this.lookupsOpenAlias,
required this.lookupsENS, required this.lookupsENS,
required this.customBitcoinFeeRate,
TransactionPriority? initialBitcoinTransactionPriority, TransactionPriority? initialBitcoinTransactionPriority,
TransactionPriority? initialMoneroTransactionPriority, TransactionPriority? initialMoneroTransactionPriority,
TransactionPriority? initialHavenTransactionPriority, TransactionPriority? initialHavenTransactionPriority,
@ -224,6 +226,9 @@ abstract class SettingsStoreBase with Store {
(bool shouldShowYatPopup) => (bool shouldShowYatPopup) =>
sharedPreferences.setBool(PreferencesKey.shouldShowYatPopup, shouldShowYatPopup)); sharedPreferences.setBool(PreferencesKey.shouldShowYatPopup, shouldShowYatPopup));
reaction((_) => shouldShowRepWarning,
(bool val) => sharedPreferences.setBool(PreferencesKey.shouldShowRepWarning, val));
defaultBuyProviders.observe((change) { defaultBuyProviders.observe((change) {
final String key = 'buyProvider_${change.key.toString()}'; final String key = 'buyProvider_${change.key.toString()}';
if (change.newValue != null) { if (change.newValue != null) {
@ -504,6 +509,11 @@ abstract class SettingsStoreBase with Store {
(PinCodeRequiredDuration pinCodeInterval) => secureStorage.write( (PinCodeRequiredDuration pinCodeInterval) => secureStorage.write(
key: SecureKey.pinTimeOutDuration, value: pinCodeInterval.value.toString())); key: SecureKey.pinTimeOutDuration, value: pinCodeInterval.value.toString()));
reaction(
(_) => customBitcoinFeeRate,
(int customBitcoinFeeRate) =>
_sharedPreferences.setInt(PreferencesKey.customBitcoinFeeRate, customBitcoinFeeRate));
this.nodes.observe((change) { this.nodes.observe((change) {
if (change.newValue != null && change.key != null) { if (change.newValue != null && change.key != null) {
_saveCurrentNode(change.newValue!, change.key!); _saveCurrentNode(change.newValue!, change.key!);
@ -530,6 +540,9 @@ abstract class SettingsStoreBase with Store {
@observable @observable
bool shouldShowYatPopup; bool shouldShowYatPopup;
@observable
bool shouldShowRepWarning;
@observable @observable
bool shouldShowMarketPlaceInDashboard; bool shouldShowMarketPlaceInDashboard;
@ -690,6 +703,9 @@ abstract class SettingsStoreBase with Store {
String deviceName; String deviceName;
@observable
int customBitcoinFeeRate;
final FlutterSecureStorage _secureStorage; final FlutterSecureStorage _secureStorage;
final SharedPreferences _sharedPreferences; final SharedPreferences _sharedPreferences;
final BackgroundTasks _backgroundTasks; final BackgroundTasks _backgroundTasks;
@ -834,6 +850,7 @@ abstract class SettingsStoreBase with Store {
sharedPreferences.getBool(PreferencesKey.lookupsUnstoppableDomains) ?? true; sharedPreferences.getBool(PreferencesKey.lookupsUnstoppableDomains) ?? true;
final lookupsOpenAlias = sharedPreferences.getBool(PreferencesKey.lookupsOpenAlias) ?? true; final lookupsOpenAlias = sharedPreferences.getBool(PreferencesKey.lookupsOpenAlias) ?? true;
final lookupsENS = sharedPreferences.getBool(PreferencesKey.lookupsENS) ?? true; final lookupsENS = sharedPreferences.getBool(PreferencesKey.lookupsENS) ?? true;
final customBitcoinFeeRate = sharedPreferences.getInt(PreferencesKey.customBitcoinFeeRate) ?? 1;
// If no value // If no value
if (pinLength == null || pinLength == 0) { if (pinLength == null || pinLength == 0) {
@ -868,6 +885,8 @@ abstract class SettingsStoreBase with Store {
final packageInfo = await PackageInfo.fromPlatform(); final packageInfo = await PackageInfo.fromPlatform();
final deviceName = await _getDeviceName() ?? ''; final deviceName = await _getDeviceName() ?? '';
final shouldShowYatPopup = sharedPreferences.getBool(PreferencesKey.shouldShowYatPopup) ?? true; final shouldShowYatPopup = sharedPreferences.getBool(PreferencesKey.shouldShowYatPopup) ?? true;
final shouldShowRepWarning =
sharedPreferences.getBool(PreferencesKey.shouldShowRepWarning) ?? true;
final generateSubaddresses = final generateSubaddresses =
sharedPreferences.getInt(PreferencesKey.autoGenerateSubaddressStatusKey); sharedPreferences.getInt(PreferencesKey.autoGenerateSubaddressStatusKey);
@ -1025,74 +1044,77 @@ abstract class SettingsStoreBase with Store {
''; '';
return SettingsStore( return SettingsStore(
secureStorage: secureStorage, secureStorage: secureStorage,
sharedPreferences: sharedPreferences, sharedPreferences: sharedPreferences,
initialShouldShowMarketPlaceInDashboard: shouldShowMarketPlaceInDashboard, initialShouldShowMarketPlaceInDashboard: shouldShowMarketPlaceInDashboard,
nodes: nodes, nodes: nodes,
powNodes: powNodes, powNodes: powNodes,
appVersion: packageInfo.version, appVersion: packageInfo.version,
deviceName: deviceName, deviceName: deviceName,
isBitcoinBuyEnabled: isBitcoinBuyEnabled, isBitcoinBuyEnabled: isBitcoinBuyEnabled,
initialFiatCurrency: currentFiatCurrency, initialFiatCurrency: currentFiatCurrency,
initialBalanceDisplayMode: currentBalanceDisplayMode, initialBalanceDisplayMode: currentBalanceDisplayMode,
initialSaveRecipientAddress: shouldSaveRecipientAddress, initialSaveRecipientAddress: shouldSaveRecipientAddress,
initialAutoGenerateSubaddressStatus: autoGenerateSubaddressStatus, initialAutoGenerateSubaddressStatus: autoGenerateSubaddressStatus,
initialMoneroSeedType: moneroSeedType, initialMoneroSeedType: moneroSeedType,
initialAppSecure: isAppSecure, initialAppSecure: isAppSecure,
initialDisableBuy: disableBuy, initialDisableBuy: disableBuy,
initialDisableSell: disableSell, initialDisableSell: disableSell,
initialDisableBulletin: disableBulletin, initialDisableBulletin: disableBulletin,
initialWalletListOrder: walletListOrder, initialWalletListOrder: walletListOrder,
initialWalletListAscending: walletListAscending, initialWalletListAscending: walletListAscending,
initialFiatMode: currentFiatApiMode, initialFiatMode: currentFiatApiMode,
initialAllowBiometricalAuthentication: allowBiometricalAuthentication, initialAllowBiometricalAuthentication: allowBiometricalAuthentication,
initialCake2FAPresetOptions: selectedCake2FAPreset, initialCake2FAPresetOptions: selectedCake2FAPreset,
initialUseTOTP2FA: useTOTP2FA, initialUseTOTP2FA: useTOTP2FA,
initialTotpSecretKey: totpSecretKey, initialTotpSecretKey: totpSecretKey,
initialFailedTokenTrial: tokenTrialNumber, initialFailedTokenTrial: tokenTrialNumber,
initialExchangeStatus: exchangeStatus, initialExchangeStatus: exchangeStatus,
initialTheme: savedTheme, initialTheme: savedTheme,
actionlistDisplayMode: actionListDisplayMode, actionlistDisplayMode: actionListDisplayMode,
initialPinLength: pinLength, initialPinLength: pinLength,
pinTimeOutDuration: pinCodeTimeOutDuration, pinTimeOutDuration: pinCodeTimeOutDuration,
seedPhraseLength: seedPhraseWordCount, seedPhraseLength: seedPhraseWordCount,
initialLanguageCode: savedLanguageCode, initialLanguageCode: savedLanguageCode,
sortBalanceBy: sortBalanceBy, sortBalanceBy: sortBalanceBy,
pinNativeTokenAtTop: pinNativeTokenAtTop, pinNativeTokenAtTop: pinNativeTokenAtTop,
useEtherscan: useEtherscan, useEtherscan: useEtherscan,
usePolygonScan: usePolygonScan, usePolygonScan: usePolygonScan,
defaultNanoRep: defaultNanoRep, defaultNanoRep: defaultNanoRep,
defaultBananoRep: defaultBananoRep, defaultBananoRep: defaultBananoRep,
lookupsTwitter: lookupsTwitter, lookupsTwitter: lookupsTwitter,
lookupsMastodon: lookupsMastodon, lookupsMastodon: lookupsMastodon,
lookupsYatService: lookupsYatService, lookupsYatService: lookupsYatService,
lookupsUnstoppableDomains: lookupsUnstoppableDomains, lookupsUnstoppableDomains: lookupsUnstoppableDomains,
lookupsOpenAlias: lookupsOpenAlias, lookupsOpenAlias: lookupsOpenAlias,
lookupsENS: lookupsENS, lookupsENS: lookupsENS,
initialMoneroTransactionPriority: moneroTransactionPriority, customBitcoinFeeRate: customBitcoinFeeRate,
initialBitcoinTransactionPriority: bitcoinTransactionPriority, initialMoneroTransactionPriority: moneroTransactionPriority,
initialHavenTransactionPriority: havenTransactionPriority, initialBitcoinTransactionPriority: bitcoinTransactionPriority,
initialLitecoinTransactionPriority: litecoinTransactionPriority, initialHavenTransactionPriority: havenTransactionPriority,
initialBitcoinCashTransactionPriority: bitcoinCashTransactionPriority, initialLitecoinTransactionPriority: litecoinTransactionPriority,
initialShouldRequireTOTP2FAForAccessingWallet: shouldRequireTOTP2FAForAccessingWallet, initialBitcoinCashTransactionPriority: bitcoinCashTransactionPriority,
initialShouldRequireTOTP2FAForSendsToContact: shouldRequireTOTP2FAForSendsToContact, initialShouldRequireTOTP2FAForAccessingWallet: shouldRequireTOTP2FAForAccessingWallet,
initialShouldRequireTOTP2FAForSendsToNonContact: shouldRequireTOTP2FAForSendsToNonContact, initialShouldRequireTOTP2FAForSendsToContact: shouldRequireTOTP2FAForSendsToContact,
initialShouldRequireTOTP2FAForSendsToInternalWallets: initialShouldRequireTOTP2FAForSendsToNonContact: shouldRequireTOTP2FAForSendsToNonContact,
shouldRequireTOTP2FAForSendsToInternalWallets, initialShouldRequireTOTP2FAForSendsToInternalWallets:
initialShouldRequireTOTP2FAForExchangesToInternalWallets: shouldRequireTOTP2FAForSendsToInternalWallets,
shouldRequireTOTP2FAForExchangesToInternalWallets, initialShouldRequireTOTP2FAForExchangesToInternalWallets:
initialShouldRequireTOTP2FAForExchangesToExternalWallets: shouldRequireTOTP2FAForExchangesToInternalWallets,
shouldRequireTOTP2FAForExchangesToExternalWallets, initialShouldRequireTOTP2FAForExchangesToExternalWallets:
initialShouldRequireTOTP2FAForAddingContacts: shouldRequireTOTP2FAForAddingContacts, shouldRequireTOTP2FAForExchangesToExternalWallets,
initialShouldRequireTOTP2FAForCreatingNewWallets: shouldRequireTOTP2FAForCreatingNewWallets, initialShouldRequireTOTP2FAForAddingContacts: shouldRequireTOTP2FAForAddingContacts,
initialShouldRequireTOTP2FAForAllSecurityAndBackupSettings: initialShouldRequireTOTP2FAForCreatingNewWallets: shouldRequireTOTP2FAForCreatingNewWallets,
shouldRequireTOTP2FAForAllSecurityAndBackupSettings, initialShouldRequireTOTP2FAForAllSecurityAndBackupSettings:
initialEthereumTransactionPriority: ethereumTransactionPriority, shouldRequireTOTP2FAForAllSecurityAndBackupSettings,
initialPolygonTransactionPriority: polygonTransactionPriority, initialEthereumTransactionPriority: ethereumTransactionPriority,
backgroundTasks: backgroundTasks, initialPolygonTransactionPriority: polygonTransactionPriority,
initialSyncMode: savedSyncMode, backgroundTasks: backgroundTasks,
initialSyncAll: savedSyncAll, initialSyncMode: savedSyncMode,
shouldShowYatPopup: shouldShowYatPopup); initialSyncAll: savedSyncAll,
shouldShowYatPopup: shouldShowYatPopup,
shouldShowRepWarning: shouldShowRepWarning,
);
} }
Future<void> reload({required Box<Node> nodeSource}) async { Future<void> reload({required Box<Node> nodeSource}) async {
@ -1160,7 +1182,8 @@ abstract class SettingsStoreBase with Store {
isAppSecure = sharedPreferences.getBool(PreferencesKey.isAppSecureKey) ?? isAppSecure; isAppSecure = sharedPreferences.getBool(PreferencesKey.isAppSecureKey) ?? isAppSecure;
disableBuy = sharedPreferences.getBool(PreferencesKey.disableBuyKey) ?? disableBuy; disableBuy = sharedPreferences.getBool(PreferencesKey.disableBuyKey) ?? disableBuy;
disableSell = sharedPreferences.getBool(PreferencesKey.disableSellKey) ?? disableSell; disableSell = sharedPreferences.getBool(PreferencesKey.disableSellKey) ?? disableSell;
disableBulletin = sharedPreferences.getBool(PreferencesKey.disableBulletinKey) ?? disableBulletin; disableBulletin =
sharedPreferences.getBool(PreferencesKey.disableBulletinKey) ?? disableBulletin;
walletListOrder = walletListOrder =
WalletListOrderType.values[sharedPreferences.getInt(PreferencesKey.walletListOrder) ?? 0]; WalletListOrderType.values[sharedPreferences.getInt(PreferencesKey.walletListOrder) ?? 0];
walletListAscending = sharedPreferences.getBool(PreferencesKey.walletListAscending) ?? true; walletListAscending = sharedPreferences.getBool(PreferencesKey.walletListAscending) ?? true;
@ -1187,6 +1210,8 @@ abstract class SettingsStoreBase with Store {
languageCode = sharedPreferences.getString(PreferencesKey.currentLanguageCode) ?? languageCode; languageCode = sharedPreferences.getString(PreferencesKey.currentLanguageCode) ?? languageCode;
shouldShowYatPopup = shouldShowYatPopup =
sharedPreferences.getBool(PreferencesKey.shouldShowYatPopup) ?? shouldShowYatPopup; sharedPreferences.getBool(PreferencesKey.shouldShowYatPopup) ?? shouldShowYatPopup;
shouldShowRepWarning =
sharedPreferences.getBool(PreferencesKey.shouldShowRepWarning) ?? shouldShowRepWarning;
sortBalanceBy = SortBalanceBy sortBalanceBy = SortBalanceBy
.values[sharedPreferences.getInt(PreferencesKey.sortBalanceBy) ?? sortBalanceBy.index]; .values[sharedPreferences.getInt(PreferencesKey.sortBalanceBy) ?? sortBalanceBy.index];
pinNativeTokenAtTop = sharedPreferences.getBool(PreferencesKey.pinNativeTokenAtTop) ?? true; pinNativeTokenAtTop = sharedPreferences.getBool(PreferencesKey.pinNativeTokenAtTop) ?? true;
@ -1201,7 +1226,7 @@ abstract class SettingsStoreBase with Store {
sharedPreferences.getBool(PreferencesKey.lookupsUnstoppableDomains) ?? true; sharedPreferences.getBool(PreferencesKey.lookupsUnstoppableDomains) ?? true;
lookupsOpenAlias = sharedPreferences.getBool(PreferencesKey.lookupsOpenAlias) ?? true; lookupsOpenAlias = sharedPreferences.getBool(PreferencesKey.lookupsOpenAlias) ?? true;
lookupsENS = sharedPreferences.getBool(PreferencesKey.lookupsENS) ?? true; lookupsENS = sharedPreferences.getBool(PreferencesKey.lookupsENS) ?? true;
customBitcoinFeeRate = sharedPreferences.getInt(PreferencesKey.customBitcoinFeeRate) ?? 1;
final nodeId = sharedPreferences.getInt(PreferencesKey.currentNodeIdKey); final nodeId = sharedPreferences.getInt(PreferencesKey.currentNodeIdKey);
final bitcoinElectrumServerId = final bitcoinElectrumServerId =
sharedPreferences.getInt(PreferencesKey.currentBitcoinElectrumSererIdKey); sharedPreferences.getInt(PreferencesKey.currentBitcoinElectrumSererIdKey);

View file

@ -46,6 +46,10 @@ abstract class ResponsiveLayoutUtilBase with Store, WidgetsBindingObserver {
(orientation == Orientation.portrait && screenWidth < screenHeight) || (orientation == Orientation.portrait && screenWidth < screenHeight) ||
(orientation == Orientation.landscape && screenWidth < screenHeight); (orientation == Orientation.landscape && screenWidth < screenHeight);
} }
bool get shouldRenderTabletUI {
return screenWidth > _kMobileThreshold && screenWidth < kDesktopMaxDashBoardWidthConstraint;
}
} }
_ResponsiveLayoutUtil _singletonResponsiveLayoutUtil = _ResponsiveLayoutUtil(); _ResponsiveLayoutUtil _singletonResponsiveLayoutUtil = _ResponsiveLayoutUtil();

View file

@ -12,6 +12,7 @@ import 'package:cake_wallet/entities/service_status.dart';
import 'package:cake_wallet/exchange/exchange_provider_description.dart'; import 'package:cake_wallet/exchange/exchange_provider_description.dart';
import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/monero/monero.dart'; import 'package:cake_wallet/monero/monero.dart';
import 'package:cake_wallet/nano/nano.dart';
import 'package:cake_wallet/store/anonpay/anonpay_transactions_store.dart'; import 'package:cake_wallet/store/anonpay/anonpay_transactions_store.dart';
import 'package:cake_wallet/store/app_store.dart'; import 'package:cake_wallet/store/app_store.dart';
import 'package:cake_wallet/store/dashboard/orders_store.dart'; import 'package:cake_wallet/store/dashboard/orders_store.dart';
@ -397,6 +398,18 @@ abstract class DashboardViewModelBase with Store {
return ""; return "";
} }
bool get showRepWarning {
if (wallet.type != WalletType.nano) {
return false;
}
if (!settingsStore.shouldShowRepWarning) {
return false;
}
return !nano!.isRepOk(wallet);
}
Future<void> reconnect() async { Future<void> reconnect() async {
final node = appStore.settingsStore.getCurrentNode(wallet.type); final node = appStore.settingsStore.getCurrentNode(wallet.type);
await wallet.connectToNode(node: node); await wallet.connectToNode(node: node);

View file

@ -54,6 +54,7 @@ abstract class HomeSettingsViewModelBase with Store {
symbol: token.title, symbol: token.title,
decimal: token.decimals, decimal: token.decimals,
contractAddress: contractAddress, contractAddress: contractAddress,
iconPath: token.iconPath,
); );
await ethereum!.addErc20Token(_balanceViewModel.wallet, erc20token); await ethereum!.addErc20Token(_balanceViewModel.wallet, erc20token);
@ -65,6 +66,7 @@ abstract class HomeSettingsViewModelBase with Store {
symbol: token.title, symbol: token.title,
decimal: token.decimals, decimal: token.decimals,
contractAddress: contractAddress, contractAddress: contractAddress,
iconPath: token.iconPath,
); );
await polygon!.addErc20Token(_balanceViewModel.wallet, polygonToken); await polygon!.addErc20Token(_balanceViewModel.wallet, polygonToken);
} }

View file

@ -12,16 +12,15 @@ import 'package:permission_handler/permission_handler.dart';
part 'node_create_or_edit_view_model.g.dart'; part 'node_create_or_edit_view_model.g.dart';
class NodeCreateOrEditViewModel = NodeCreateOrEditViewModelBase class NodeCreateOrEditViewModel = NodeCreateOrEditViewModelBase with _$NodeCreateOrEditViewModel;
with _$NodeCreateOrEditViewModel;
abstract class NodeCreateOrEditViewModelBase with Store { abstract class NodeCreateOrEditViewModelBase with Store {
NodeCreateOrEditViewModelBase( NodeCreateOrEditViewModelBase(this._nodeSource, this._walletType, this._settingsStore)
this._nodeSource, this._walletType, this._settingsStore)
: state = InitialExecutionState(), : state = InitialExecutionState(),
connectionState = InitialExecutionState(), connectionState = InitialExecutionState(),
useSSL = false, useSSL = false,
address = '', address = '',
path = '',
port = '', port = '',
login = '', login = '',
password = '', password = '',
@ -35,6 +34,9 @@ abstract class NodeCreateOrEditViewModelBase with Store {
@observable @observable
String address; String address;
@observable
String path;
@observable @observable
String port; String port;
@ -84,6 +86,7 @@ abstract class NodeCreateOrEditViewModelBase with Store {
@action @action
void reset() { void reset() {
address = ''; address = '';
path = '';
port = ''; port = '';
login = ''; login = '';
password = ''; password = '';
@ -99,6 +102,9 @@ abstract class NodeCreateOrEditViewModelBase with Store {
@action @action
void setAddress(String val) => address = val; void setAddress(String val) => address = val;
@action
void setPath(String val) => path = val;
@action @action
void setLogin(String val) => login = val; void setLogin(String val) => login = val;
@ -121,6 +127,7 @@ abstract class NodeCreateOrEditViewModelBase with Store {
Future<void> save({Node? editingNode, bool saveAsCurrent = false}) async { Future<void> save({Node? editingNode, bool saveAsCurrent = false}) async {
final node = Node( final node = Node(
uri: uri, uri: uri,
path: path,
type: _walletType, type: _walletType,
login: login, login: login,
password: password, password: password,
@ -151,6 +158,7 @@ abstract class NodeCreateOrEditViewModelBase with Store {
Future<void> connect() async { Future<void> connect() async {
final node = Node( final node = Node(
uri: uri, uri: uri,
path: path,
type: _walletType, type: _walletType,
login: login, login: login,
password: password, password: password,
@ -183,7 +191,7 @@ abstract class NodeCreateOrEditViewModelBase with Store {
Future<void> scanQRCodeForNewNode(BuildContext context) async { Future<void> scanQRCodeForNewNode(BuildContext context) async {
try { try {
bool isCameraPermissionGranted = bool isCameraPermissionGranted =
await PermissionHandler.checkPermission(Permission.camera, context); await PermissionHandler.checkPermission(Permission.camera, context);
if (!isCameraPermissionGranted) return; if (!isCameraPermissionGranted) return;
String code = await presentQRScanner(); String code = await presentQRScanner();
@ -198,7 +206,7 @@ abstract class NodeCreateOrEditViewModelBase with Store {
} }
final userInfo = uri.userInfo.split(':'); final userInfo = uri.userInfo.split(':');
if (userInfo.length < 2) { if (userInfo.length < 2) {
throw Exception('Unexpected scan QR code value: Value is invalid'); throw Exception('Unexpected scan QR code value: Value is invalid');
} }
@ -207,8 +215,11 @@ abstract class NodeCreateOrEditViewModelBase with Store {
final rpcPassword = userInfo[1]; final rpcPassword = userInfo[1];
final ipAddress = uri.host; final ipAddress = uri.host;
final port = uri.port.toString(); final port = uri.port.toString();
final path = uri.path;
setAddress(ipAddress); setAddress(ipAddress);
setPath(path);
setPassword(rpcPassword); setPassword(rpcPassword);
setLogin(rpcUser); setLogin(rpcUser);
setPort(port); setPort(port);

View file

@ -121,11 +121,19 @@ abstract class OutputBase with Store {
return solana!.getEstimateFees(_wallet) ?? 0.0; return solana!.getEstimateFees(_wallet) ?? 0.0;
} }
final fee = _wallet.calculateEstimatedFee( int? fee = _wallet.calculateEstimatedFee(
_settingsStore.priority[_wallet.type]!, formattedCryptoAmount); _settingsStore.priority[_wallet.type]!, formattedCryptoAmount);
if (_wallet.type == WalletType.bitcoin || if (_wallet.type == WalletType.bitcoin) {
_wallet.type == WalletType.litecoin || if (_settingsStore.priority[_wallet.type] == bitcoin!.getBitcoinTransactionPriorityCustom()) {
fee = bitcoin!.getFeeAmountWithFeeRate(
_settingsStore.customBitcoinFeeRate, formattedCryptoAmount, 1, 1);
}
return bitcoin!.formatterBitcoinAmountToDouble(amount: fee);
}
if (_wallet.type == WalletType.litecoin ||
_wallet.type == WalletType.bitcoinCash) { _wallet.type == WalletType.bitcoinCash) {
return bitcoin!.formatterBitcoinAmountToDouble(amount: fee); return bitcoin!.formatterBitcoinAmountToDouble(amount: fee);
} }

View file

@ -39,6 +39,7 @@ import 'package:cake_wallet/entities/parsed_address.dart';
import 'package:cake_wallet/bitcoin/bitcoin.dart'; import 'package:cake_wallet/bitcoin/bitcoin.dart';
import 'package:cake_wallet/haven/haven.dart'; import 'package:cake_wallet/haven/haven.dart';
import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/generated/i18n.dart';
import 'package:collection/collection.dart';
part 'send_view_model.g.dart'; part 'send_view_model.g.dart';
@ -68,9 +69,12 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
_settingsStore = appStore.settingsStore, _settingsStore = appStore.settingsStore,
fiatFromSettings = appStore.settingsStore.fiatCurrency, fiatFromSettings = appStore.settingsStore.fiatCurrency,
super(appStore: appStore) { super(appStore: appStore) {
if (wallet.type == WalletType.bitcoin &&
_settingsStore.priority[wallet.type] == bitcoinTransactionPriorityCustom) {
setTransactionPriority(bitcoinTransactionPriorityMedium);
}
final priority = _settingsStore.priority[wallet.type]; final priority = _settingsStore.priority[wallet.type];
final priorities = priorityForWalletType(wallet.type); final priorities = priorityForWalletType(wallet.type);
if (!priorityForWalletType(wallet.type).contains(priority) && priorities.isNotEmpty) { if (!priorityForWalletType(wallet.type).contains(priority) && priorities.isNotEmpty) {
_settingsStore.priority[wallet.type] = priorities.first; _settingsStore.priority[wallet.type] = priorities.first;
} }
@ -152,6 +156,21 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
return priority; return priority;
} }
int? getCustomPriorityIndex(List<TransactionPriority> priorities) {
if (wallet.type == WalletType.bitcoin) {
final customItem = priorities
.firstWhereOrNull((element) => element == bitcoin!.getBitcoinTransactionPriorityCustom());
return customItem != null ? priorities.indexOf(customItem) : null;
}
return null;
}
@computed
int get customBitcoinFeeRate => _settingsStore.customBitcoinFeeRate;
void set customBitcoinFeeRate(int value) => _settingsStore.customBitcoinFeeRate = value;
CryptoCurrency get currency => wallet.currency; CryptoCurrency get currency => wallet.currency;
Validator<String> get amountValidator => Validator<String> get amountValidator =>
@ -323,6 +342,29 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
return null; return null;
} }
@action
Future<void> replaceByFee(String txId, String newFee) async {
state = IsExecutingState();
final isSufficient = await bitcoin!.isChangeSufficientForFee(wallet, txId, newFee);
if (!isSufficient) {
state = AwaitingConfirmationState(
title: S.current.confirm_fee_deduction,
message: S.current.confirm_fee_deduction_content,
onConfirm: () async {
pendingTransaction = await bitcoin!.replaceByFee(wallet, txId, newFee);
state = ExecutedSuccessfullyState();
},
onCancel: () {
state = FailureState('Insufficient change for fee');
});
} else {
pendingTransaction = await bitcoin!.replaceByFee(wallet, txId, newFee);
state = ExecutedSuccessfullyState();
}
}
@action @action
Future<void> commitTransaction() async { Future<void> commitTransaction() async {
if (pendingTransaction == null) { if (pendingTransaction == null) {
@ -380,7 +422,8 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
case WalletType.bitcoin: case WalletType.bitcoin:
case WalletType.litecoin: case WalletType.litecoin:
case WalletType.bitcoinCash: case WalletType.bitcoinCash:
return bitcoin!.createBitcoinTransactionCredentials(outputs, priority: priority!); return bitcoin!.createBitcoinTransactionCredentials(outputs,
priority: priority!, feeRate: customBitcoinFeeRate);
case WalletType.monero: case WalletType.monero:
return monero! return monero!
@ -406,9 +449,14 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
} }
} }
String displayFeeRate(dynamic priority) { String displayFeeRate(dynamic priority, int? customValue) {
final _priority = priority as TransactionPriority; final _priority = priority as TransactionPriority;
if (walletType == WalletType.bitcoin) {
final rate = bitcoin!.getFeeRate(wallet, _priority);
return bitcoin!.bitcoinTransactionPriorityWithLabel(_priority, rate, customRate: customValue);
}
if (isElectrumWallet) { if (isElectrumWallet) {
final rate = bitcoin!.getFeeRate(wallet, _priority); final rate = bitcoin!.getFeeRate(wallet, _priority);
return bitcoin!.bitcoinTransactionPriorityWithLabel(_priority, rate); return bitcoin!.bitcoinTransactionPriorityWithLabel(_priority, rate);
@ -420,6 +468,12 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
bool _isEqualCurrency(String currency) => bool _isEqualCurrency(String currency) =>
wallet.balance.keys.any((e) => currency.toLowerCase() == e.title.toLowerCase()); wallet.balance.keys.any((e) => currency.toLowerCase() == e.title.toLowerCase());
TransactionPriority get bitcoinTransactionPriorityCustom =>
bitcoin!.getBitcoinTransactionPriorityCustom();
TransactionPriority get bitcoinTransactionPriorityMedium =>
bitcoin!.getBitcoinTransactionPriorityMedium();
@action @action
void onClose() => _settingsStore.fiatCurrency = fiatFromSettings; void onClose() => _settingsStore.fiatCurrency = fiatFromSettings;
@ -449,7 +503,9 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
address = output.address; address = output.address;
} }
if (address.isNotEmpty && !contactAddresses.contains(address)) { if (address.isNotEmpty &&
!contactAddresses.contains(address) &&
selectedCryptoCurrency.raw != -1) {
return ContactRecord( return ContactRecord(
contactListViewModel.contactSource, contactListViewModel.contactSource,
Contact( Contact(

View file

@ -11,6 +11,7 @@ import 'package:cw_core/wallet_base.dart';
import 'package:cw_core/wallet_type.dart'; import 'package:cw_core/wallet_type.dart';
import 'package:mobx/mobx.dart'; import 'package:mobx/mobx.dart';
import 'package:package_info/package_info.dart'; import 'package:package_info/package_info.dart';
import 'package:collection/collection.dart';
part 'other_settings_view_model.g.dart'; part 'other_settings_view_model.g.dart';
@ -77,6 +78,8 @@ abstract class OtherSettingsViewModelBase with Store {
ProviderType get sellProviderType => ProviderType get sellProviderType =>
_settingsStore.defaultSellProviders[walletType] ?? ProviderType.askEachTime; _settingsStore.defaultSellProviders[walletType] ?? ProviderType.askEachTime;
String getDisplayPriority(dynamic priority) { String getDisplayPriority(dynamic priority) {
final _priority = priority as TransactionPriority; final _priority = priority as TransactionPriority;
@ -90,6 +93,19 @@ abstract class OtherSettingsViewModelBase with Store {
return priority.toString(); return priority.toString();
} }
String getDisplayBitcoinPriority(dynamic priority, int customValue) {
final _priority = priority as TransactionPriority;
if (_wallet.type == WalletType.bitcoin ||
_wallet.type == WalletType.litecoin ||
_wallet.type == WalletType.bitcoinCash) {
final rate = bitcoin!.getFeeRate(_wallet, _priority);
return bitcoin!.bitcoinTransactionPriorityWithLabel(_priority, rate, customRate: customValue);
}
return priority.toString();
}
String getBuyProviderType(dynamic buyProviderType) { String getBuyProviderType(dynamic buyProviderType) {
final _buyProviderType = buyProviderType as ProviderType; final _buyProviderType = buyProviderType as ProviderType;
return _buyProviderType == ProviderType.askEachTime return _buyProviderType == ProviderType.askEachTime
@ -105,7 +121,24 @@ abstract class OtherSettingsViewModelBase with Store {
} }
void onDisplayPrioritySelected(TransactionPriority priority) => void onDisplayPrioritySelected(TransactionPriority priority) =>
_settingsStore.priority[_wallet.type] = priority; _settingsStore.priority[walletType] = priority;
void onDisplayBitcoinPrioritySelected(TransactionPriority priority, double customValue) {
if (_wallet.type == WalletType.bitcoin) {
_settingsStore.customBitcoinFeeRate = customValue.round();
}
_settingsStore.priority[_wallet.type] = priority;
}
@computed
double get customBitcoinFeeRate => _settingsStore.customBitcoinFeeRate.toDouble();
int? get customPriorityItemIndex {
final priorities = priorityForWalletType(walletType);
final customItem = priorities
.firstWhereOrNull((element) => element == bitcoin!.getBitcoinTransactionPriorityCustom());
return customItem != null ? priorities.indexOf(customItem) : null;
}
@action @action
ProviderType onBuyProviderTypeSelected(ProviderType buyProviderType) => ProviderType onBuyProviderTypeSelected(ProviderType buyProviderType) =>

View file

@ -44,6 +44,8 @@ abstract class PrivacySettingsViewModelBase with Store {
_wallet.type == WalletType.litecoin || _wallet.type == WalletType.litecoin ||
_wallet.type == WalletType.bitcoinCash; _wallet.type == WalletType.bitcoinCash;
bool get isMoneroWallet => _wallet.type == WalletType.monero;
@computed @computed
bool get shouldSaveRecipientAddress => _settingsStore.shouldSaveRecipientAddress; bool get shouldSaveRecipientAddress => _settingsStore.shouldSaveRecipientAddress;

View file

@ -1,20 +1,27 @@
import 'package:cw_core/wallet_base.dart'; import 'package:cake_wallet/bitcoin/bitcoin.dart';
import 'package:cw_core/transaction_info.dart'; import 'package:cake_wallet/entities/priority_for_wallet_type.dart';
import 'package:cw_core/wallet_type.dart'; import 'package:cake_wallet/entities/transaction_description.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/monero/monero.dart';
import 'package:cake_wallet/src/screens/transaction_details/blockexplorer_list_item.dart';
import 'package:cake_wallet/src/screens/transaction_details/rbf_details_list_fee_picker_item.dart';
import 'package:cake_wallet/src/screens/transaction_details/standart_list_item.dart'; import 'package:cake_wallet/src/screens/transaction_details/standart_list_item.dart';
import 'package:cake_wallet/src/screens/transaction_details/textfield_list_item.dart'; import 'package:cake_wallet/src/screens/transaction_details/textfield_list_item.dart';
import 'package:cake_wallet/src/screens/transaction_details/transaction_details_list_item.dart'; import 'package:cake_wallet/src/screens/transaction_details/transaction_details_list_item.dart';
import 'package:cake_wallet/src/screens/transaction_details/blockexplorer_list_item.dart'; import 'package:cake_wallet/src/screens/transaction_details/transaction_expandable_list_item.dart';
import 'package:cw_core/transaction_direction.dart'; import 'package:cake_wallet/store/settings_store.dart';
import 'package:cake_wallet/utils/date_formatter.dart'; import 'package:cake_wallet/utils/date_formatter.dart';
import 'package:cake_wallet/entities/transaction_description.dart'; import 'package:cake_wallet/view_model/send/send_view_model.dart';
import 'package:collection/collection.dart';
import 'package:cw_core/transaction_direction.dart';
import 'package:cw_core/transaction_info.dart';
import 'package:cw_core/transaction_priority.dart';
import 'package:cw_core/wallet_base.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:hive/hive.dart'; import 'package:hive/hive.dart';
import 'package:intl/src/intl/date_format.dart'; import 'package:intl/src/intl/date_format.dart';
import 'package:mobx/mobx.dart'; import 'package:mobx/mobx.dart';
import 'package:cake_wallet/store/settings_store.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:url_launcher/url_launcher.dart'; import 'package:url_launcher/url_launcher.dart';
import 'package:cake_wallet/monero/monero.dart';
part 'transaction_details_view_model.g.dart'; part 'transaction_details_view_model.g.dart';
@ -26,8 +33,11 @@ abstract class TransactionDetailsViewModelBase with Store {
{required this.transactionInfo, {required this.transactionInfo,
required this.transactionDescriptionBox, required this.transactionDescriptionBox,
required this.wallet, required this.wallet,
required this.settingsStore}) required this.settingsStore,
required this.sendViewModel})
: items = [], : items = [],
RBFListItems = [],
newFee = 0,
isRecipientAddressShown = false, isRecipientAddressShown = false,
showRecipientAddress = settingsStore.shouldSaveRecipientAddress { showRecipientAddress = settingsStore.shouldSaveRecipientAddress {
final dateFormat = DateFormatter.withCurrentLocal(); final dateFormat = DateFormatter.withCurrentLocal();
@ -38,6 +48,10 @@ abstract class TransactionDetailsViewModelBase with Store {
_addMoneroListItems(tx, dateFormat); _addMoneroListItems(tx, dateFormat);
break; break;
case WalletType.bitcoin: case WalletType.bitcoin:
_addElectrumListItems(tx, dateFormat);
_addBumpFeesListItems(tx);
_checkForRBF();
break;
case WalletType.litecoin: case WalletType.litecoin:
case WalletType.bitcoinCash: case WalletType.bitcoinCash:
_addElectrumListItems(tx, dateFormat); _addElectrumListItems(tx, dateFormat);
@ -114,10 +128,20 @@ abstract class TransactionDetailsViewModelBase with Store {
final Box<TransactionDescription> transactionDescriptionBox; final Box<TransactionDescription> transactionDescriptionBox;
final SettingsStore settingsStore; final SettingsStore settingsStore;
final WalletBase wallet; final WalletBase wallet;
final SendViewModel sendViewModel;
final List<TransactionDetailsListItem> items; final List<TransactionDetailsListItem> items;
final List<TransactionDetailsListItem> RBFListItems;
bool showRecipientAddress; bool showRecipientAddress;
bool isRecipientAddressShown; bool isRecipientAddressShown;
int newFee;
TransactionPriority? transactionPriority;
@observable
bool _canReplaceByFee = false;
@computed
bool get canReplaceByFee => _canReplaceByFee /*&& transactionInfo.confirmations <= 0*/;
String _explorerUrl(WalletType type, String txId) { String _explorerUrl(WalletType type, String txId) {
switch (type) { switch (type) {
@ -323,4 +347,88 @@ abstract class TransactionDetailsViewModelBase with Store {
items.addAll(_items); items.addAll(_items);
} }
void _addBumpFeesListItems(TransactionInfo tx) {
transactionPriority = bitcoin!.getBitcoinTransactionPriorityMedium();
newFee = bitcoin!.getFeeAmountForPriority(
wallet,
bitcoin!.getBitcoinTransactionPriorityMedium(),
transactionInfo.inputAddresses?.length ?? 1,
transactionInfo.outputAddresses?.length ?? 1);
RBFListItems.add(StandartListItem(
title: S.current.old_fee,
value: tx.feeFormatted() ?? '0.0'));
final priorities = priorityForWalletType(wallet.type);
final selectedItem = priorities.indexOf(sendViewModel.transactionPriority);
final customItem = priorities.firstWhereOrNull(
(element) => element == sendViewModel.bitcoinTransactionPriorityCustom);
final customItemIndex = customItem != null ? priorities.indexOf(customItem) : null;
RBFListItems.add(StandardPickerListItem(
title: S.current.estimated_new_fee,
value: bitcoin!.formatterBitcoinAmountToString(amount: newFee) + ' ${walletTypeToCryptoCurrency(wallet.type)}',
items: priorityForWalletType(wallet.type),
customValue: settingsStore.customBitcoinFeeRate.toDouble(),
selectedIdx: selectedItem,
customItemIndex: customItemIndex ?? 0,
displayItem: (dynamic priority, double sliderValue) =>
sendViewModel.displayFeeRate(priority, sliderValue.round()),
onSliderChanged: (double newValue) =>
setNewFee(value: newValue, priority: transactionPriority!),
onItemSelected: (dynamic item) {
transactionPriority = item as TransactionPriority;
return setNewFee(priority: transactionPriority!);
}));
if (transactionInfo.inputAddresses != null) {
RBFListItems.add(StandardExpandableListItem(
title: S.current.inputs, expandableItems: transactionInfo.inputAddresses!));
}
if (transactionInfo.outputAddresses != null) {
RBFListItems.add(StandardExpandableListItem(
title: S.current.outputs, expandableItems: transactionInfo.outputAddresses!));
}
}
@action
Future<void> _checkForRBF() async {
if (wallet.type == WalletType.bitcoin &&
transactionInfo.direction == TransactionDirection.outgoing) {
if (await bitcoin!.canReplaceByFee(wallet, transactionInfo.id)) {
_canReplaceByFee = true;
}
}
}
String setNewFee({double? value, required TransactionPriority priority}) {
newFee = priority == bitcoin!.getBitcoinTransactionPriorityCustom() && value != null
? bitcoin!.getFeeAmountWithFeeRate(
wallet,
value.round(),
transactionInfo.inputAddresses?.length ?? 1,
transactionInfo.outputAddresses?.length ?? 1)
: bitcoin!.getFeeAmountForPriority(
wallet,
priority,
transactionInfo.inputAddresses?.length ?? 1,
transactionInfo.outputAddresses?.length ?? 1);
return bitcoin!.formatterBitcoinAmountToString(amount: newFee);
}
void replaceByFee(String newFee) => sendViewModel.replaceByFee(transactionInfo.id, newFee);
@computed
String get pendingTransactionFiatAmountValueFormatted => sendViewModel.isFiatDisabled
? ''
: sendViewModel.pendingTransactionFiatAmount + ' ' + sendViewModel.fiat.title;
@computed
String get pendingTransactionFeeFiatAmountFormatted => sendViewModel.isFiatDisabled
? ''
: sendViewModel.pendingTransactionFeeFiatAmount + ' ' + sendViewModel.fiat.title;
} }

View file

@ -223,10 +223,6 @@ abstract class WalletAddressListViewModelBase extends WalletChangeListenerViewMo
return S.current.addresses; return S.current.addresses;
} }
if (isAutoGenerateSubaddressEnabled) {
return hasAccounts ? S.current.accounts : S.current.account;
}
return hasAccounts ? S.current.accounts_subaddresses : S.current.addresses; return hasAccounts ? S.current.accounts_subaddresses : S.current.addresses;
} }

View file

@ -59,6 +59,7 @@
"auth_store_incorrect_password": "PIN خطأ", "auth_store_incorrect_password": "PIN خطأ",
"authenticated": "تم المصادقة", "authenticated": "تم المصادقة",
"authentication": "المصادقة", "authentication": "المصادقة",
"auto_generate_addresses": "تلقائي توليد العناوين",
"auto_generate_subaddresses": "تلقائي توليد subddresses", "auto_generate_subaddresses": "تلقائي توليد subddresses",
"automatic": "تلقائي", "automatic": "تلقائي",
"available_balance": "الرصيد المتوفر", "available_balance": "الرصيد المتوفر",
@ -81,6 +82,7 @@
"breez_warning_disruption": "خدمة Breez تواجه حاليًا قضايا. الرجاء معاودة المحاولة في وقت لاحق.", "breez_warning_disruption": "خدمة Breez تواجه حاليًا قضايا. الرجاء معاودة المحاولة في وقت لاحق.",
"breez_warning_maintenance": "تمر خدمة Breez حاليًا بالصيانة. الرجاء معاودة المحاولة في وقت لاحق.", "breez_warning_maintenance": "تمر خدمة Breez حاليًا بالصيانة. الرجاء معاودة المحاولة في وقت لاحق.",
"bright_theme": "مشرق", "bright_theme": "مشرق",
"bump_fee": "رسوم عثرة",
"buy": "اشتري", "buy": "اشتري",
"buy_alert_content": ".ﺎﻬﻴﻟﺇ ﻞﻳﺪﺒﺘﻟﺍ ﻭﺃ Monero ﻭﺃ Litecoin ﻭﺃ Ethereum ﻭﺃ Bitcoin ﺔﻈﻔﺤﻣ ءﺎﺸﻧﺇ ﻰﺟﺮﻳ .", "buy_alert_content": ".ﺎﻬﻴﻟﺇ ﻞﻳﺪﺒﺘﻟﺍ ﻭﺃ Monero ﻭﺃ Litecoin ﻭﺃ Ethereum ﻭﺃ Bitcoin ﺔﻈﻔﺤﻣ ءﺎﺸﻧﺇ ﻰﺟﺮﻳ .",
"buy_bitcoin": "شراء Bitcoin", "buy_bitcoin": "شراء Bitcoin",
@ -135,6 +137,8 @@
"confirm": "تأكيد", "confirm": "تأكيد",
"confirm_delete_template": "سيؤدي هذا الإجراء إلى حذف هذا القالب. هل ترغب في الاستمرار؟", "confirm_delete_template": "سيؤدي هذا الإجراء إلى حذف هذا القالب. هل ترغب في الاستمرار؟",
"confirm_delete_wallet": "سيؤدي هذا الإجراء إلى حذف هذه المحفظة. هل ترغب في الاستمرار؟", "confirm_delete_wallet": "سيؤدي هذا الإجراء إلى حذف هذه المحفظة. هل ترغب في الاستمرار؟",
"confirm_fee_deduction": "تأكيد خصم الرسوم",
"confirm_fee_deduction_content": "هل توافق على خصم الرسوم من الإخراج؟",
"confirm_sending": "تأكيد الإرسال", "confirm_sending": "تأكيد الإرسال",
"confirmations": "التأكيدات", "confirmations": "التأكيدات",
"confirmed": "رصيد مؤكد", "confirmed": "رصيد مؤكد",
@ -174,6 +178,7 @@
"debit_card": "بطاقة ائتمان", "debit_card": "بطاقة ائتمان",
"debit_card_terms": "يخضع تخزين واستخدام رقم بطاقة الدفع الخاصة بك (وبيانات الاعتماد المقابلة لرقم بطاقة الدفع الخاصة بك) في هذه المحفظة الرقمية لشروط وأحكام اتفاقية حامل البطاقة المعمول بها مع جهة إصدار بطاقة الدفع ، كما هو معمول به من وقت لآخر.", "debit_card_terms": "يخضع تخزين واستخدام رقم بطاقة الدفع الخاصة بك (وبيانات الاعتماد المقابلة لرقم بطاقة الدفع الخاصة بك) في هذه المحفظة الرقمية لشروط وأحكام اتفاقية حامل البطاقة المعمول بها مع جهة إصدار بطاقة الدفع ، كما هو معمول به من وقت لآخر.",
"decimal_places_error": "عدد كبير جدًا من المنازل العشرية", "decimal_places_error": "عدد كبير جدًا من المنازل العشرية",
"decimals_cannot_be_zero": "الرمز العشري لا يمكن أن يكون الصفر.",
"default_buy_provider": "مزود شراء الافتراضي", "default_buy_provider": "مزود شراء الافتراضي",
"default_sell_provider": "ﻲﺿﺍﺮﺘﻓﻻﺍ ﻊﻴﺒﻟﺍ ﺩﻭﺰﻣ", "default_sell_provider": "ﻲﺿﺍﺮﺘﻓﻻﺍ ﻊﻴﺒﻟﺍ ﺩﻭﺰﻣ",
"delete": "حذف", "delete": "حذف",
@ -214,6 +219,7 @@
"edit_token": "تحرير الرمز المميز", "edit_token": "تحرير الرمز المميز",
"electrum_address_disclaimer": "نقوم بإنشاء عناوين جديدة في كل مرة تستخدم فيها عنوانًا ، لكن العناوين السابقة تستمر في العمل", "electrum_address_disclaimer": "نقوم بإنشاء عناوين جديدة في كل مرة تستخدم فيها عنوانًا ، لكن العناوين السابقة تستمر في العمل",
"email_address": "عنوان البريد الالكترونى", "email_address": "عنوان البريد الالكترونى",
"enable_replace_by_fee": "تمكين الاستبدال",
"enabled": "ممكنة", "enabled": "ممكنة",
"enter_amount": "أدخل المبلغ", "enter_amount": "أدخل المبلغ",
"enter_backup_password": "أدخل كلمة المرور الاحتياطية هنا", "enter_backup_password": "أدخل كلمة المرور الاحتياطية هنا",
@ -250,6 +256,7 @@
"errorGettingCredentials": "ﺩﺎﻤﺘﻋﻻﺍ ﺕﺎﻧﺎﻴﺑ ﻰﻠﻋ ﻝﻮﺼﺤﻟﺍ ءﺎﻨﺛﺃ ﺄﻄﺧ ﺙﺪﺣ :ﻞﺸﻓ", "errorGettingCredentials": "ﺩﺎﻤﺘﻋﻻﺍ ﺕﺎﻧﺎﻴﺑ ﻰﻠﻋ ﻝﻮﺼﺤﻟﺍ ءﺎﻨﺛﺃ ﺄﻄﺧ ﺙﺪﺣ :ﻞﺸﻓ",
"errorSigningTransaction": "ﺔﻠﻣﺎﻌﻤﻟﺍ ﻊﻴﻗﻮﺗ ءﺎﻨﺛﺃ ﺄﻄﺧ ﺙﺪﺣ", "errorSigningTransaction": "ﺔﻠﻣﺎﻌﻤﻟﺍ ﻊﻴﻗﻮﺗ ءﺎﻨﺛﺃ ﺄﻄﺧ ﺙﺪﺣ",
"estimated": "مُقدَّر", "estimated": "مُقدَّر",
"estimated_new_fee": "رسوم جديدة مقدرة",
"etherscan_history": "Etherscan تاريخ", "etherscan_history": "Etherscan تاريخ",
"event": "ﺙﺪﺣ", "event": "ﺙﺪﺣ",
"events": "ﺙﺍﺪﺣﻷﺍ", "events": "ﺙﺍﺪﺣﻷﺍ",
@ -316,6 +323,7 @@
"in_store": "في المتجر", "in_store": "في المتجر",
"incoming": "الواردة", "incoming": "الواردة",
"incorrect_seed": "النص الذي تم إدخاله غير صالح.", "incorrect_seed": "النص الذي تم إدخاله غير صالح.",
"inputs": "المدخلات",
"introducing_cake_pay": "نقدم لكم Cake Pay!", "introducing_cake_pay": "نقدم لكم Cake Pay!",
"invalid_input": "مدخل غير صالح", "invalid_input": "مدخل غير صالح",
"invoice": "فاتورة", "invoice": "فاتورة",
@ -358,6 +366,8 @@
"moonpay_alert_text": "يجب أن تكون قيمة المبلغ أكبر من أو تساوي ${minAmount} ${fiatCurrency}", "moonpay_alert_text": "يجب أن تكون قيمة المبلغ أكبر من أو تساوي ${minAmount} ${fiatCurrency}",
"more_options": "المزيد من الخيارات", "more_options": "المزيد من الخيارات",
"name": "ﻢﺳﺍ", "name": "ﻢﺳﺍ",
"nano_current_rep": "الممثل الحالي",
"nano_pick_new_rep": "اختر ممثلًا جديدًا",
"narrow": "ضيق", "narrow": "ضيق",
"new_first_wallet_text": "حافظ بسهولة على أمان العملة المشفرة", "new_first_wallet_text": "حافظ بسهولة على أمان العملة المشفرة",
"new_node_testing": "تجربة العقدة الجديدة", "new_node_testing": "تجربة العقدة الجديدة",
@ -390,6 +400,7 @@
"offer_expires_in": "ينتهي العرض في:", "offer_expires_in": "ينتهي العرض في:",
"offline": "غير متصل على الانترنت", "offline": "غير متصل على الانترنت",
"ok": "حسناً", "ok": "حسناً",
"old_fee": "الرسوم القديمة",
"onion_link": "رابط البصل", "onion_link": "رابط البصل",
"online": "متصل", "online": "متصل",
"onramper_option_description": "شراء بسرعة التشفير مع العديد من طرق الدفع. متوفر في معظم البلدان. ينتشر وتختلف الرسوم.", "onramper_option_description": "شراء بسرعة التشفير مع العديد من طرق الدفع. متوفر في معظم البلدان. ينتشر وتختلف الرسوم.",
@ -406,6 +417,7 @@
"outdated_electrum_wallet_description": "محافظ Bitcoin الجديدة التي تم إنشاؤها في Cake الآن سييد مكونة من 24 كلمة. من الضروري أن تقوم بإنشاء محفظة Bitcoin جديدة وتحويل جميع أموالك إلى المحفظة الجديدة المكونة من 24 كلمة ، والتوقف عن استخدام محافظ سييد مكونة من 12 كلمة. يرجى القيام بذلك على الفور لتأمين أموالك.", "outdated_electrum_wallet_description": "محافظ Bitcoin الجديدة التي تم إنشاؤها في Cake الآن سييد مكونة من 24 كلمة. من الضروري أن تقوم بإنشاء محفظة Bitcoin جديدة وتحويل جميع أموالك إلى المحفظة الجديدة المكونة من 24 كلمة ، والتوقف عن استخدام محافظ سييد مكونة من 12 كلمة. يرجى القيام بذلك على الفور لتأمين أموالك.",
"outdated_electrum_wallet_receive_warning": "إذا كانت هذه المحفظة تحتوي على سييد مكونة من 12 كلمة وتم إنشاؤها في Cake ، فلا تقم بإيداع Bitcoin في هذه المحفظة. قد يتم فقد أي BTC تم تحويله إلى هذه المحفظة. قم بإنشاء محفظة جديدة مكونة من 24 كلمة (انقر فوق القائمة في الجزء العلوي الأيمن ، وحدد محافظ ، واختر إنشاء محفظة جديدة ، ثم حدد Bitcoin) وقم على الفور بنقل BTC الخاص بك هناك. محافظ BTC الجديدة (24 كلمة) من Cake آمنة", "outdated_electrum_wallet_receive_warning": "إذا كانت هذه المحفظة تحتوي على سييد مكونة من 12 كلمة وتم إنشاؤها في Cake ، فلا تقم بإيداع Bitcoin في هذه المحفظة. قد يتم فقد أي BTC تم تحويله إلى هذه المحفظة. قم بإنشاء محفظة جديدة مكونة من 24 كلمة (انقر فوق القائمة في الجزء العلوي الأيمن ، وحدد محافظ ، واختر إنشاء محفظة جديدة ، ثم حدد Bitcoin) وقم على الفور بنقل BTC الخاص بك هناك. محافظ BTC الجديدة (24 كلمة) من Cake آمنة",
"outgoing": "الصادره", "outgoing": "الصادره",
"outputs": "المخرجات",
"overwrite_amount": "تغير المبلغ", "overwrite_amount": "تغير المبلغ",
"pairingInvalidEvent": "ﺢﻟﺎﺻ ﺮﻴﻏ ﺙﺪﺣ ﻥﺍﺮﻗﺇ", "pairingInvalidEvent": "ﺢﻟﺎﺻ ﺮﻴﻏ ﺙﺪﺣ ﻥﺍﺮﻗﺇ",
"password": "كلمة المرور", "password": "كلمة المرور",
@ -464,6 +476,8 @@
"remove_node": "إزالة العقدة", "remove_node": "إزالة العقدة",
"remove_node_message": "هل أنت متأكد أنك تريد إزالة العقدة المحددة؟", "remove_node_message": "هل أنت متأكد أنك تريد إزالة العقدة المحددة؟",
"rename": "إعادة تسمية", "rename": "إعادة تسمية",
"rep_warning": "تحذير تمثيلي",
"rep_warning_sub": "لا يبدو أن ممثلك في وضع جيد. اضغط هنا لاختيار واحدة جديدة",
"require_for_adding_contacts": "تتطلب إضافة جهات اتصال", "require_for_adding_contacts": "تتطلب إضافة جهات اتصال",
"require_for_all_security_and_backup_settings": "مطلوب لجميع إعدادات الأمان والنسخ الاحتياطي", "require_for_all_security_and_backup_settings": "مطلوب لجميع إعدادات الأمان والنسخ الاحتياطي",
"require_for_assessing_wallet": "تتطلب الوصول إلى المحفظة", "require_for_assessing_wallet": "تتطلب الوصول إلى المحفظة",
@ -741,6 +755,7 @@
"unspent_coins_details_title": "تفاصيل العملات الغير المنفقة", "unspent_coins_details_title": "تفاصيل العملات الغير المنفقة",
"unspent_coins_title": "العملات الغير المنفقة", "unspent_coins_title": "العملات الغير المنفقة",
"unsupported_asset": ".ﻡﻮﻋﺪﻣ ﻞﺻﺃ ﻉﻮﻧ ﻦﻣ ﺔﻈﻔﺤﻣ ﻰﻟﺇ ﻞﻳﺪﺒﺘﻟﺍ ﻭﺃ ءﺎﺸﻧﺇ ﻰﺟﺮﻳ .ﻞﺻﻷﺍ ﺍﺬﻬﻟ ءﺍﺮﺟﻹﺍ ﺍﺬﻫ ﻢﻋﺪﻧ ﻻ ﻦﺤﻧ", "unsupported_asset": ".ﻡﻮﻋﺪﻣ ﻞﺻﺃ ﻉﻮﻧ ﻦﻣ ﺔﻈﻔﺤﻣ ﻰﻟﺇ ﻞﻳﺪﺒﺘﻟﺍ ﻭﺃ ءﺎﺸﻧﺇ ﻰﺟﺮﻳ .ﻞﺻﻷﺍ ﺍﺬﻬﻟ ءﺍﺮﺟﻹﺍ ﺍﺬﻫ ﻢﻋﺪﻧ ﻻ ﻦﺤﻧ",
"uptime": "مدة التشغيل",
"upto": "حتى ${value}", "upto": "حتى ${value}",
"use": "التبديل إلى", "use": "التبديل إلى",
"use_card_info_three": "استخدم البطاقة الرقمية عبر الإنترنت أو مع طرق الدفع غير التلامسية.", "use_card_info_three": "استخدم البطاقة الرقمية عبر الإنترنت أو مع طرق الدفع غير التلامسية.",
@ -757,6 +772,7 @@
"view_key_private": "مفتاح العرض (خاص)", "view_key_private": "مفتاح العرض (خاص)",
"view_key_public": "مفتاح العرض (عام)", "view_key_public": "مفتاح العرض (عام)",
"view_transaction_on": "عرض العملية على", "view_transaction_on": "عرض العملية على",
"voting_weight": "وزن التصويت",
"waitFewSecondForTxUpdate": "ﺕﻼﻣﺎﻌﻤﻟﺍ ﻞﺠﺳ ﻲﻓ ﺔﻠﻣﺎﻌﻤﻟﺍ ﺲﻜﻌﻨﺗ ﻰﺘﺣ ﻥﺍﻮﺛ ﻊﻀﺒﻟ ﺭﺎﻈﺘﻧﻻﺍ ﻰﺟﺮﻳ", "waitFewSecondForTxUpdate": "ﺕﻼﻣﺎﻌﻤﻟﺍ ﻞﺠﺳ ﻲﻓ ﺔﻠﻣﺎﻌﻤﻟﺍ ﺲﻜﻌﻨﺗ ﻰﺘﺣ ﻥﺍﻮﺛ ﻊﻀﺒﻟ ﺭﺎﻈﺘﻧﻻﺍ ﻰﺟﺮﻳ",
"wallet_keys": "سييد المحفظة / المفاتيح", "wallet_keys": "سييد المحفظة / المفاتيح",
"wallet_list_create_new_wallet": "إنشاء محفظة جديدة", "wallet_list_create_new_wallet": "إنشاء محفظة جديدة",

View file

@ -59,6 +59,7 @@
"auth_store_incorrect_password": "Грешен PIN", "auth_store_incorrect_password": "Грешен PIN",
"authenticated": "Удостоверено", "authenticated": "Удостоверено",
"authentication": "Удостоверяване", "authentication": "Удостоверяване",
"auto_generate_addresses": "Автоматично генериране на адреси",
"auto_generate_subaddresses": "Автоматично генериране на подадреси", "auto_generate_subaddresses": "Автоматично генериране на подадреси",
"automatic": "Автоматично", "automatic": "Автоматично",
"available_balance": "Наличен баланс", "available_balance": "Наличен баланс",
@ -81,6 +82,7 @@
"breez_warning_disruption": "В момента услугата Breez изпитва проблеми. Моля, опитайте отново по-късно.", "breez_warning_disruption": "В момента услугата Breez изпитва проблеми. Моля, опитайте отново по-късно.",
"breez_warning_maintenance": "Понастоящем услугата Breez се подлага на поддръжка. Моля, опитайте отново по-късно.", "breez_warning_maintenance": "Понастоящем услугата Breez се подлага на поддръжка. Моля, опитайте отново по-късно.",
"bright_theme": "Ярко", "bright_theme": "Ярко",
"bump_fee": "Такса за бум",
"buy": "Купуване", "buy": "Купуване",
"buy_alert_content": "В момента поддържаме само закупуването на Bitcoin, Ethereum, Litecoin и Monero. Моля, създайте или превключете към своя портфейл Bitcoin, Ethereum, Litecoin или Monero.", "buy_alert_content": "В момента поддържаме само закупуването на Bitcoin, Ethereum, Litecoin и Monero. Моля, създайте или превключете към своя портфейл Bitcoin, Ethereum, Litecoin или Monero.",
"buy_bitcoin": "Купуване на Bitcoin", "buy_bitcoin": "Купуване на Bitcoin",
@ -135,6 +137,8 @@
"confirm": "Потвърждаване", "confirm": "Потвърждаване",
"confirm_delete_template": "Този шаблон ще бъде изтрит. Искате ли да продължите?", "confirm_delete_template": "Този шаблон ще бъде изтрит. Искате ли да продължите?",
"confirm_delete_wallet": "Този портфейл ще бъде изтрит. Искате ли да продължите?", "confirm_delete_wallet": "Този портфейл ще бъде изтрит. Искате ли да продължите?",
"confirm_fee_deduction": "Потвърдете приспадането на таксите",
"confirm_fee_deduction_content": "Съгласни ли сте да приспадате таксата от продукцията?",
"confirm_sending": "Потвърждаване на изпращането", "confirm_sending": "Потвърждаване на изпращането",
"confirmations": "потвърждения", "confirmations": "потвърждения",
"confirmed": "Потвърден баланс", "confirmed": "Потвърден баланс",
@ -174,6 +178,7 @@
"debit_card": "Дебитна карта", "debit_card": "Дебитна карта",
"debit_card_terms": "Съхранението и използването на данните от вашата платежна карта в този дигитален портфейл подлежат на условията на съответното съгласие за картодържец от издателя на картата.", "debit_card_terms": "Съхранението и използването на данните от вашата платежна карта в този дигитален портфейл подлежат на условията на съответното съгласие за картодържец от издателя на картата.",
"decimal_places_error": "Твърде много знаци след десетичната запетая", "decimal_places_error": "Твърде много знаци след десетичната запетая",
"decimals_cannot_be_zero": "Десетичната точка не може да бъде нула.",
"default_buy_provider": "Доставчик по подразбиране купува", "default_buy_provider": "Доставчик по подразбиране купува",
"default_sell_provider": "Доставчик за продажба по подразбиране", "default_sell_provider": "Доставчик за продажба по подразбиране",
"delete": "Изтрий", "delete": "Изтрий",
@ -214,6 +219,7 @@
"edit_token": "Редактиране на токена", "edit_token": "Редактиране на токена",
"electrum_address_disclaimer": "Нови адреси се генерират всеки път, когато използвате този, но и предишните продължават да работят", "electrum_address_disclaimer": "Нови адреси се генерират всеки път, когато използвате този, но и предишните продължават да работят",
"email_address": "Имейл адрес", "email_address": "Имейл адрес",
"enable_replace_by_fee": "Активиране на замяна по забрана",
"enabled": "Активирано", "enabled": "Активирано",
"enter_amount": "Въведете сума", "enter_amount": "Въведете сума",
"enter_backup_password": "Въведете парола за възстановяване", "enter_backup_password": "Въведете парола за възстановяване",
@ -250,6 +256,7 @@
"errorGettingCredentials": "Неуспешно: Грешка при получаване на идентификационни данни", "errorGettingCredentials": "Неуспешно: Грешка при получаване на идентификационни данни",
"errorSigningTransaction": "Възникна грешка при подписване на транзакция", "errorSigningTransaction": "Възникна грешка при подписване на транзакция",
"estimated": "Изчислено", "estimated": "Изчислено",
"estimated_new_fee": "Прогнозна нова такса",
"etherscan_history": "История на Etherscan", "etherscan_history": "История на Etherscan",
"event": "Събитие", "event": "Събитие",
"events": "събития", "events": "събития",
@ -316,6 +323,7 @@
"in_store": "In Store", "in_store": "In Store",
"incoming": "Входящи", "incoming": "Входящи",
"incorrect_seed": "Въведеният текст е невалиден.", "incorrect_seed": "Въведеният текст е невалиден.",
"inputs": "Входове",
"introducing_cake_pay": "Запознайте се с Cake Pay!", "introducing_cake_pay": "Запознайте се с Cake Pay!",
"invalid_input": "Невалиден вход", "invalid_input": "Невалиден вход",
"invoice": "Фактура", "invoice": "Фактура",
@ -358,6 +366,8 @@
"moonpay_alert_text": "Сумата трябва да бъде най-малко ${minAmount} ${fiatCurrency}", "moonpay_alert_text": "Сумата трябва да бъде най-малко ${minAmount} ${fiatCurrency}",
"more_options": "Още настройки", "more_options": "Още настройки",
"name": "Име", "name": "Име",
"nano_current_rep": "Настоящ представител",
"nano_pick_new_rep": "Изберете нов представител",
"narrow": "Тесен", "narrow": "Тесен",
"new_first_wallet_text": "Лесно пазете криптовалутата си в безопасност", "new_first_wallet_text": "Лесно пазете криптовалутата си в безопасност",
"new_node_testing": "Тестване на нов node", "new_node_testing": "Тестване на нов node",
@ -390,6 +400,7 @@
"offer_expires_in": "Предложението изтича след: ", "offer_expires_in": "Предложението изтича след: ",
"offline": "Офлайн", "offline": "Офлайн",
"ok": "Ок", "ok": "Ок",
"old_fee": "Стара такса",
"onion_link": "Лукова връзка", "onion_link": "Лукова връзка",
"online": "Онлайн", "online": "Онлайн",
"onramper_option_description": "Бързо купувайте криптовалута с много методи за плащане. Предлага се в повечето страни. Разпространенията и таксите варират.", "onramper_option_description": "Бързо купувайте криптовалута с много методи за плащане. Предлага се в повечето страни. Разпространенията и таксите варират.",
@ -406,6 +417,7 @@
"outdated_electrum_wallet_description": "Нови Bitcoin портфейли, създадени в Cake, сега имат seed от 24 думи. Трябва да създадете нов Bitcoin адрес и да прехвърлите всичките си средства в него и веднага да спрете използването на стари портфейли. Моля, напревете това незабавно, за да подсигурите средствата си.", "outdated_electrum_wallet_description": "Нови Bitcoin портфейли, създадени в Cake, сега имат seed от 24 думи. Трябва да създадете нов Bitcoin адрес и да прехвърлите всичките си средства в него и веднага да спрете използването на стари портфейли. Моля, напревете това незабавно, за да подсигурите средствата си.",
"outdated_electrum_wallet_receive_warning": "Ако този адрес има seed от 12 думи и е създаден чрез Cake, НЕ добавяйте Bitcoin в него. Всякакъв Bitcoin, изпратен на този адрес, може да бъде загубен завинаги. Създайте нов портфейл от 24 думи (натиснете менюто горе, вдясно, изберете Портфейли, изберете Създаване на нов портфейл, след това изберете Bitcoin) и НЕЗАБАВНО преместете своя Bitcoin там. Нови (такива с 24 думи) Bitcoin портфейли от Cake са надеждни", "outdated_electrum_wallet_receive_warning": "Ако този адрес има seed от 12 думи и е създаден чрез Cake, НЕ добавяйте Bitcoin в него. Всякакъв Bitcoin, изпратен на този адрес, може да бъде загубен завинаги. Създайте нов портфейл от 24 думи (натиснете менюто горе, вдясно, изберете Портфейли, изберете Създаване на нов портфейл, след това изберете Bitcoin) и НЕЗАБАВНО преместете своя Bitcoin там. Нови (такива с 24 думи) Bitcoin портфейли от Cake са надеждни",
"outgoing": "Изходящи", "outgoing": "Изходящи",
"outputs": "Изходи",
"overwrite_amount": "Промени сума", "overwrite_amount": "Промени сума",
"pairingInvalidEvent": "Невалидно събитие при сдвояване", "pairingInvalidEvent": "Невалидно събитие при сдвояване",
"password": "Парола", "password": "Парола",
@ -464,6 +476,8 @@
"remove_node": "Премахни node", "remove_node": "Премахни node",
"remove_node_message": "Сигурни ли сте, че искате да премахнете избрания node?", "remove_node_message": "Сигурни ли сте, че искате да премахнете избрания node?",
"rename": "Промяна на името", "rename": "Промяна на името",
"rep_warning": "Представително предупреждение",
"rep_warning_sub": "Вашият представител изглежда не е в добро състояние. Докоснете тук, за да изберете нов",
"require_for_adding_contacts": "Изисква се за добавяне на контакти", "require_for_adding_contacts": "Изисква се за добавяне на контакти",
"require_for_all_security_and_backup_settings": "Изисква се за всички настройки за сигурност и архивиране", "require_for_all_security_and_backup_settings": "Изисква се за всички настройки за сигурност и архивиране",
"require_for_assessing_wallet": "Изискване за достъп до портфейла", "require_for_assessing_wallet": "Изискване за достъп до портфейла",
@ -741,6 +755,7 @@
"unspent_coins_details_title": "Подробности за неизползваните монети", "unspent_coins_details_title": "Подробности за неизползваните монети",
"unspent_coins_title": "Неизползвани монети", "unspent_coins_title": "Неизползвани монети",
"unsupported_asset": "Не поддържаме това действие за този актив. Моля, създайте или преминете към портфейл от поддържан тип актив.", "unsupported_asset": "Не поддържаме това действие за този актив. Моля, създайте или преминете към портфейл от поддържан тип актив.",
"uptime": "Време за работа",
"upto": "до ${value}", "upto": "до ${value}",
"use": "Смяна на ", "use": "Смяна на ",
"use_card_info_three": "Използвайте дигиталната карта онлайн или чрез безконтактен метод на плащане.", "use_card_info_three": "Използвайте дигиталната карта онлайн или чрез безконтактен метод на плащане.",
@ -757,6 +772,7 @@
"view_key_private": "View key (таен)", "view_key_private": "View key (таен)",
"view_key_public": "View key (публичен)", "view_key_public": "View key (публичен)",
"view_transaction_on": "Вижте транзакция на ", "view_transaction_on": "Вижте транзакция на ",
"voting_weight": "Тегло на гласуване",
"waitFewSecondForTxUpdate": "Моля, изчакайте няколко секунди, докато транзакцията се отрази в историята на транзакциите", "waitFewSecondForTxUpdate": "Моля, изчакайте няколко секунди, докато транзакцията се отрази в историята на транзакциите",
"wallet_keys": "Seed/keys на портфейла", "wallet_keys": "Seed/keys на портфейла",
"wallet_list_create_new_wallet": "Създаване на нов портфейл", "wallet_list_create_new_wallet": "Създаване на нов портфейл",

View file

@ -59,6 +59,7 @@
"auth_store_incorrect_password": "Nesprávný PIN", "auth_store_incorrect_password": "Nesprávný PIN",
"authenticated": "Ověřeno", "authenticated": "Ověřeno",
"authentication": "Ověřování", "authentication": "Ověřování",
"auto_generate_addresses": "Automatické generování adres",
"auto_generate_subaddresses": "Automaticky generovat podadresy", "auto_generate_subaddresses": "Automaticky generovat podadresy",
"automatic": "Automatický", "automatic": "Automatický",
"available_balance": "Dostupný zůstatek", "available_balance": "Dostupný zůstatek",
@ -81,6 +82,7 @@
"breez_warning_disruption": "Služba Breez v současné době má problémy. Prosím zkuste to znovu později.", "breez_warning_disruption": "Služba Breez v současné době má problémy. Prosím zkuste to znovu později.",
"breez_warning_maintenance": "Služba Breez v současné době prochází údržbou. Prosím zkuste to znovu později.", "breez_warning_maintenance": "Služba Breez v současné době prochází údržbou. Prosím zkuste to znovu později.",
"bright_theme": "Jasný", "bright_theme": "Jasný",
"bump_fee": "Bump Fee",
"buy": "Koupit", "buy": "Koupit",
"buy_alert_content": "V současné době podporujeme pouze nákup bitcoinů, etherea, litecoinů a monero. Vytvořte nebo přepněte na svou peněženku bitcoinů, etherea, litecoinů nebo monero.", "buy_alert_content": "V současné době podporujeme pouze nákup bitcoinů, etherea, litecoinů a monero. Vytvořte nebo přepněte na svou peněženku bitcoinů, etherea, litecoinů nebo monero.",
"buy_bitcoin": "Nakoupit Bitcoin", "buy_bitcoin": "Nakoupit Bitcoin",
@ -135,6 +137,8 @@
"confirm": "Potvrdit", "confirm": "Potvrdit",
"confirm_delete_template": "Tato akce smaže tuto šablonu. Přejete si pokračovat?", "confirm_delete_template": "Tato akce smaže tuto šablonu. Přejete si pokračovat?",
"confirm_delete_wallet": "Tato akce smaže tuto peněženku. Přejete si pokračovat?", "confirm_delete_wallet": "Tato akce smaže tuto peněženku. Přejete si pokračovat?",
"confirm_fee_deduction": "Potvrďte odpočet poplatků",
"confirm_fee_deduction_content": "Souhlasíte s odečtením poplatku z výstupu?",
"confirm_sending": "Potvrdit odeslání", "confirm_sending": "Potvrdit odeslání",
"confirmations": "Potvrzení", "confirmations": "Potvrzení",
"confirmed": "Potvrzený zůstatek", "confirmed": "Potvrzený zůstatek",
@ -174,6 +178,7 @@
"debit_card": "Debetní karta", "debit_card": "Debetní karta",
"debit_card_terms": "Uložení a použití vašeho čísla platební karty (a přihlašovací údaje k vašemu číslu karty) v této digitální peněžence se řídí Obchodními podmínkami smlouvy příslušného držitele karty s vydavatelem karty (v jejich nejaktuálnější verzi).", "debit_card_terms": "Uložení a použití vašeho čísla platební karty (a přihlašovací údaje k vašemu číslu karty) v této digitální peněžence se řídí Obchodními podmínkami smlouvy příslušného držitele karty s vydavatelem karty (v jejich nejaktuálnější verzi).",
"decimal_places_error": "Příliš mnoho desetinných míst", "decimal_places_error": "Příliš mnoho desetinných míst",
"decimals_cannot_be_zero": "Desetinná desetinná škola nemůže být nulová.",
"default_buy_provider": "Výchozí poskytovatel nákupu", "default_buy_provider": "Výchozí poskytovatel nákupu",
"default_sell_provider": "Výchozí poskytovatel prodeje", "default_sell_provider": "Výchozí poskytovatel prodeje",
"delete": "Smazat", "delete": "Smazat",
@ -214,6 +219,7 @@
"edit_token": "Upravit token", "edit_token": "Upravit token",
"electrum_address_disclaimer": "Po každém použití je generována nová adresa, ale předchozí adresy také stále fungují", "electrum_address_disclaimer": "Po každém použití je generována nová adresa, ale předchozí adresy také stále fungují",
"email_address": "E-mailová adresa", "email_address": "E-mailová adresa",
"enable_replace_by_fee": "Povolit výměnu podle poplatku",
"enabled": "Povoleno", "enabled": "Povoleno",
"enter_amount": "Zadejte částku", "enter_amount": "Zadejte částku",
"enter_backup_password": "Zde zadejte své heslo pro zálohy", "enter_backup_password": "Zde zadejte své heslo pro zálohy",
@ -250,6 +256,7 @@
"errorGettingCredentials": "Selhalo: Chyba při získávání přihlašovacích údajů", "errorGettingCredentials": "Selhalo: Chyba při získávání přihlašovacích údajů",
"errorSigningTransaction": "Při podepisování transakce došlo k chybě", "errorSigningTransaction": "Při podepisování transakce došlo k chybě",
"estimated": "Odhadováno", "estimated": "Odhadováno",
"estimated_new_fee": "Odhadovaný nový poplatek",
"etherscan_history": "Historie Etherscanu", "etherscan_history": "Historie Etherscanu",
"event": "událost", "event": "událost",
"events": "Události", "events": "Události",
@ -316,6 +323,7 @@
"in_store": "V obchodě", "in_store": "V obchodě",
"incoming": "Příchozí", "incoming": "Příchozí",
"incorrect_seed": "Zadaný text není správný.", "incorrect_seed": "Zadaný text není správný.",
"inputs": "Vstupy",
"introducing_cake_pay": "Představujeme Cake Pay!", "introducing_cake_pay": "Představujeme Cake Pay!",
"invalid_input": "Neplatný vstup", "invalid_input": "Neplatný vstup",
"invoice": "Faktura", "invoice": "Faktura",
@ -358,6 +366,8 @@
"moonpay_alert_text": "Částka musí být větší nebo rovna ${minAmount} ${fiatCurrency}", "moonpay_alert_text": "Částka musí být větší nebo rovna ${minAmount} ${fiatCurrency}",
"more_options": "Více možností", "more_options": "Více možností",
"name": "název", "name": "název",
"nano_current_rep": "Současný zástupce",
"nano_pick_new_rep": "Vyberte nového zástupce",
"narrow": "Úzký", "narrow": "Úzký",
"new_first_wallet_text": "Snadno udržujte svou kryptoměnu v bezpečí", "new_first_wallet_text": "Snadno udržujte svou kryptoměnu v bezpečí",
"new_node_testing": "Testování nového uzlu", "new_node_testing": "Testování nového uzlu",
@ -390,6 +400,7 @@
"offer_expires_in": "Nabídka vyprší: ", "offer_expires_in": "Nabídka vyprší: ",
"offline": "Offline", "offline": "Offline",
"ok": "OK", "ok": "OK",
"old_fee": "Starý poplatek",
"onion_link": "Cibulový odkaz", "onion_link": "Cibulový odkaz",
"online": "Online", "online": "Online",
"onramper_option_description": "Rychle si koupte krypto s mnoha metodami plateb. K dispozici ve většině zemí. Rozpětí a poplatky se liší.", "onramper_option_description": "Rychle si koupte krypto s mnoha metodami plateb. K dispozici ve většině zemí. Rozpětí a poplatky se liší.",
@ -406,6 +417,7 @@
"outdated_electrum_wallet_description": "Nové Bitcoinové peněženky vytvořené v Cake mají nyní seed se 24 slovy. Je třeba si vytvořit novou Bitcoinovou peněženku se 24 slovy, převést na ni všechny prostředky a přestat používat seed se 12 slovy. Prosím udělejte to hned pro zabezpečení svých prostředků.", "outdated_electrum_wallet_description": "Nové Bitcoinové peněženky vytvořené v Cake mají nyní seed se 24 slovy. Je třeba si vytvořit novou Bitcoinovou peněženku se 24 slovy, převést na ni všechny prostředky a přestat používat seed se 12 slovy. Prosím udělejte to hned pro zabezpečení svých prostředků.",
"outdated_electrum_wallet_receive_warning": "Tato peněženka má seed se 12 slovy a byla vytvořena pomocí Cake, NEUKLÁDEJTE Bitcoin na tuto peněženku. Jakékoliv BTC převedené na tuto peněženku může být ztraceno. Vytvořte si novou peněženku s 24 slovy (otevřete menu vpravo nahoře, vyberte Peněženky, zvolte Vytvořit novou peněženku a pak zvolte Bitcoin) a IHNED tam přesuňte své BTC. Nové (24-slovní) BTC peněženky z Cake jsou bezpečné", "outdated_electrum_wallet_receive_warning": "Tato peněženka má seed se 12 slovy a byla vytvořena pomocí Cake, NEUKLÁDEJTE Bitcoin na tuto peněženku. Jakékoliv BTC převedené na tuto peněženku může být ztraceno. Vytvořte si novou peněženku s 24 slovy (otevřete menu vpravo nahoře, vyberte Peněženky, zvolte Vytvořit novou peněženku a pak zvolte Bitcoin) a IHNED tam přesuňte své BTC. Nové (24-slovní) BTC peněženky z Cake jsou bezpečné",
"outgoing": "Odchozí", "outgoing": "Odchozí",
"outputs": "Výstupy",
"overwrite_amount": "Přepsat částku", "overwrite_amount": "Přepsat částku",
"pairingInvalidEvent": "Neplatná událost párování", "pairingInvalidEvent": "Neplatná událost párování",
"password": "Heslo", "password": "Heslo",
@ -464,6 +476,8 @@
"remove_node": "Odstranit uzel", "remove_node": "Odstranit uzel",
"remove_node_message": "Opravdu chcete odstranit označený uzel?", "remove_node_message": "Opravdu chcete odstranit označený uzel?",
"rename": "Přejmenovat", "rename": "Přejmenovat",
"rep_warning": "Reprezentativní varování",
"rep_warning_sub": "Zdá se, že váš zástupce není v dobrém stavu. Klepnutím zde vyberte nový",
"require_for_adding_contacts": "Vyžadovat pro přidání kontaktů", "require_for_adding_contacts": "Vyžadovat pro přidání kontaktů",
"require_for_all_security_and_backup_settings": "Vyžadovat všechna nastavení zabezpečení a zálohování", "require_for_all_security_and_backup_settings": "Vyžadovat všechna nastavení zabezpečení a zálohování",
"require_for_assessing_wallet": "Vyžadovat pro přístup k peněžence", "require_for_assessing_wallet": "Vyžadovat pro přístup k peněžence",
@ -741,6 +755,7 @@
"unspent_coins_details_title": "Podrobnosti o neutracených mincích", "unspent_coins_details_title": "Podrobnosti o neutracených mincích",
"unspent_coins_title": "Neutracené mince", "unspent_coins_title": "Neutracené mince",
"unsupported_asset": "Tuto akci u tohoto díla nepodporujeme. Vytvořte nebo přepněte na peněženku podporovaného typu aktiv.", "unsupported_asset": "Tuto akci u tohoto díla nepodporujeme. Vytvořte nebo přepněte na peněženku podporovaného typu aktiv.",
"uptime": "Uptime",
"upto": "až ${value}", "upto": "až ${value}",
"use": "Přepnout na ", "use": "Přepnout na ",
"use_card_info_three": "Použijte tuto digitální kartu online nebo bezkontaktními platebními metodami.", "use_card_info_three": "Použijte tuto digitální kartu online nebo bezkontaktními platebními metodami.",
@ -757,6 +772,7 @@
"view_key_private": "Klíč pro zobrazení (soukromý)", "view_key_private": "Klíč pro zobrazení (soukromý)",
"view_key_public": "Klíč pro zobrazení (veřejný)", "view_key_public": "Klíč pro zobrazení (veřejný)",
"view_transaction_on": "Zobrazit transakci na ", "view_transaction_on": "Zobrazit transakci na ",
"voting_weight": "Hlasová váha",
"waitFewSecondForTxUpdate": "Počkejte několik sekund, než se transakce projeví v historii transakcí", "waitFewSecondForTxUpdate": "Počkejte několik sekund, než se transakce projeví v historii transakcí",
"wallet_keys": "Seed/klíče peněženky", "wallet_keys": "Seed/klíče peněženky",
"wallet_list_create_new_wallet": "Vytvořit novou peněženku", "wallet_list_create_new_wallet": "Vytvořit novou peněženku",

View file

@ -59,6 +59,7 @@
"auth_store_incorrect_password": "Falsche PIN", "auth_store_incorrect_password": "Falsche PIN",
"authenticated": "Authentifiziert", "authenticated": "Authentifiziert",
"authentication": "Authentifizierung", "authentication": "Authentifizierung",
"auto_generate_addresses": "Automatisch generieren Adressen",
"auto_generate_subaddresses": "Unteradressen automatisch generieren", "auto_generate_subaddresses": "Unteradressen automatisch generieren",
"automatic": "Automatisch", "automatic": "Automatisch",
"available_balance": "Verfügbares Guthaben", "available_balance": "Verfügbares Guthaben",
@ -81,6 +82,7 @@
"breez_warning_disruption": "Der Breez -Service hat derzeit Probleme. Bitte versuchen Sie es später erneut.", "breez_warning_disruption": "Der Breez -Service hat derzeit Probleme. Bitte versuchen Sie es später erneut.",
"breez_warning_maintenance": "Der Breez -Service wird derzeit gewartet. Bitte versuchen Sie es später erneut.", "breez_warning_maintenance": "Der Breez -Service wird derzeit gewartet. Bitte versuchen Sie es später erneut.",
"bright_theme": "Strahlend hell", "bright_theme": "Strahlend hell",
"bump_fee": "Beulengebühr",
"buy": "Kaufen", "buy": "Kaufen",
"buy_alert_content": "Derzeit unterstützen wir nur den Kauf von Bitcoin, Ethereum, Litecoin und Monero. Bitte erstellen Sie Ihr Bitcoin-, Ethereum-, Litecoin- oder Monero-Wallet oder wechseln Sie zu diesem.", "buy_alert_content": "Derzeit unterstützen wir nur den Kauf von Bitcoin, Ethereum, Litecoin und Monero. Bitte erstellen Sie Ihr Bitcoin-, Ethereum-, Litecoin- oder Monero-Wallet oder wechseln Sie zu diesem.",
"buy_bitcoin": "Bitcoin kaufen", "buy_bitcoin": "Bitcoin kaufen",
@ -135,6 +137,8 @@
"confirm": "Bestätigen", "confirm": "Bestätigen",
"confirm_delete_template": "Diese Aktion löscht diese Vorlage. Möchten Sie fortfahren?", "confirm_delete_template": "Diese Aktion löscht diese Vorlage. Möchten Sie fortfahren?",
"confirm_delete_wallet": "Diese Aktion löscht diese Wallet. Möchten Sie fortfahren?", "confirm_delete_wallet": "Diese Aktion löscht diese Wallet. Möchten Sie fortfahren?",
"confirm_fee_deduction": "Gebührenabzug bestätigen",
"confirm_fee_deduction_content": "Stimmen Sie zu, die Gebühr von der Ausgabe abzuziehen?",
"confirm_sending": "Senden bestätigen", "confirm_sending": "Senden bestätigen",
"confirmations": "Bestätigungen", "confirmations": "Bestätigungen",
"confirmed": "Bestätigter Saldo", "confirmed": "Bestätigter Saldo",
@ -174,6 +178,7 @@
"debit_card": "Debitkarte", "debit_card": "Debitkarte",
"debit_card_terms": "Die Speicherung und Nutzung Ihrer Zahlungskartennummer (und Ihrer Zahlungskartennummer entsprechenden Anmeldeinformationen) in dieser digitalen Geldbörse unterliegt den Allgemeinen Geschäftsbedingungen des geltenden Karteninhabervertrags mit dem Zahlungskartenaussteller, gültig ab von Zeit zu Zeit.", "debit_card_terms": "Die Speicherung und Nutzung Ihrer Zahlungskartennummer (und Ihrer Zahlungskartennummer entsprechenden Anmeldeinformationen) in dieser digitalen Geldbörse unterliegt den Allgemeinen Geschäftsbedingungen des geltenden Karteninhabervertrags mit dem Zahlungskartenaussteller, gültig ab von Zeit zu Zeit.",
"decimal_places_error": "Zu viele Nachkommastellen", "decimal_places_error": "Zu viele Nachkommastellen",
"decimals_cannot_be_zero": "Token -Dezimalzahl kann nicht Null sein.",
"default_buy_provider": "Standard-Kaufanbieter", "default_buy_provider": "Standard-Kaufanbieter",
"default_sell_provider": "Standard-Verkaufsanbieter", "default_sell_provider": "Standard-Verkaufsanbieter",
"delete": "Löschen", "delete": "Löschen",
@ -214,6 +219,7 @@
"edit_token": "Token bearbeiten", "edit_token": "Token bearbeiten",
"electrum_address_disclaimer": "Wir generieren jedes Mal neue Adressen, wenn Sie eine verwenden, aber vorherige Adressen funktionieren weiterhin", "electrum_address_disclaimer": "Wir generieren jedes Mal neue Adressen, wenn Sie eine verwenden, aber vorherige Adressen funktionieren weiterhin",
"email_address": "E-Mail-Adresse", "email_address": "E-Mail-Adresse",
"enable_replace_by_fee": "Aktivieren Sie Ersatz für Fee",
"enabled": "Ermöglicht", "enabled": "Ermöglicht",
"enter_amount": "Betrag eingeben", "enter_amount": "Betrag eingeben",
"enter_backup_password": "Sicherungskennwort hier eingeben", "enter_backup_password": "Sicherungskennwort hier eingeben",
@ -250,6 +256,7 @@
"errorGettingCredentials": "Fehlgeschlagen: Fehler beim Abrufen der Anmeldeinformationen", "errorGettingCredentials": "Fehlgeschlagen: Fehler beim Abrufen der Anmeldeinformationen",
"errorSigningTransaction": "Beim Signieren der Transaktion ist ein Fehler aufgetreten", "errorSigningTransaction": "Beim Signieren der Transaktion ist ein Fehler aufgetreten",
"estimated": "Geschätzt", "estimated": "Geschätzt",
"estimated_new_fee": "Geschätzte neue Gebühr",
"etherscan_history": "Etherscan-Geschichte", "etherscan_history": "Etherscan-Geschichte",
"event": "Ereignis", "event": "Ereignis",
"events": "Veranstaltungen", "events": "Veranstaltungen",
@ -316,6 +323,7 @@
"in_store": "Im Geschäft", "in_store": "Im Geschäft",
"incoming": "Eingehend", "incoming": "Eingehend",
"incorrect_seed": "Der eingegebene Text ist ungültig.", "incorrect_seed": "Der eingegebene Text ist ungültig.",
"inputs": "Eingänge",
"introducing_cake_pay": "Einführung von Cake Pay!", "introducing_cake_pay": "Einführung von Cake Pay!",
"invalid_input": "Ungültige Eingabe", "invalid_input": "Ungültige Eingabe",
"invoice": "Rechnung", "invoice": "Rechnung",
@ -358,6 +366,8 @@
"moonpay_alert_text": "Der Wert des Betrags muss größer oder gleich ${minAmount} ${fiatCurrency} sein", "moonpay_alert_text": "Der Wert des Betrags muss größer oder gleich ${minAmount} ${fiatCurrency} sein",
"more_options": "Weitere Optionen", "more_options": "Weitere Optionen",
"name": "Name", "name": "Name",
"nano_current_rep": "Aktueller Vertreter",
"nano_pick_new_rep": "Wählen Sie einen neuen Vertreter aus",
"narrow": "Eng", "narrow": "Eng",
"new_first_wallet_text": "Bewahren Sie Ihre Kryptowährung einfach sicher auf", "new_first_wallet_text": "Bewahren Sie Ihre Kryptowährung einfach sicher auf",
"new_node_testing": "Neuen Knoten testen", "new_node_testing": "Neuen Knoten testen",
@ -390,6 +400,7 @@
"offer_expires_in": "Angebot läuft ab in: ", "offer_expires_in": "Angebot läuft ab in: ",
"offline": "offline", "offline": "offline",
"ok": "OK", "ok": "OK",
"old_fee": "Alte Gebühr",
"onion_link": "Zwiebel-Link", "onion_link": "Zwiebel-Link",
"online": "online", "online": "online",
"onramper_option_description": "Kaufen Sie schnell Krypto mit vielen Zahlungsmethoden. In den meisten Ländern erhältlich. Spreads und Gebühren variieren.", "onramper_option_description": "Kaufen Sie schnell Krypto mit vielen Zahlungsmethoden. In den meisten Ländern erhältlich. Spreads und Gebühren variieren.",
@ -406,6 +417,7 @@
"outdated_electrum_wallet_description": "Neue Bitcoin-Wallets, die in Cake erstellt wurden, haben jetzt einen 24-Wort-Seed. Sie müssen eine neue Bitcoin-Wallet erstellen, Ihr gesamtes Geld in die neue 24-Wort-Wallet überweisen und keine Wallet mit einem 12-Wort-Seed mehr verwenden. Bitte tun Sie dies sofort, um Ihr Geld zu sichern.", "outdated_electrum_wallet_description": "Neue Bitcoin-Wallets, die in Cake erstellt wurden, haben jetzt einen 24-Wort-Seed. Sie müssen eine neue Bitcoin-Wallet erstellen, Ihr gesamtes Geld in die neue 24-Wort-Wallet überweisen und keine Wallet mit einem 12-Wort-Seed mehr verwenden. Bitte tun Sie dies sofort, um Ihr Geld zu sichern.",
"outdated_electrum_wallet_receive_warning": "Wenn diese Wallet einen 12-Wort-Seed hat und in Cake erstellt wurde, zahlen Sie KEINE Bitcoins in diese Wallet ein. Alle auf diese Wallet übertragenen BTC können verloren gehen. Erstellen Sie eine neue 24-Wort-Wallet (tippen Sie auf das Menü oben rechts, wählen Sie Wallets, wählen Sie Neue Wallet erstellen und dann Bitcoin) und verschieben Sie Ihre BTC SOFORT dorthin. Neue (24-Wort-)BTC-Wallets von Cake sind sicher", "outdated_electrum_wallet_receive_warning": "Wenn diese Wallet einen 12-Wort-Seed hat und in Cake erstellt wurde, zahlen Sie KEINE Bitcoins in diese Wallet ein. Alle auf diese Wallet übertragenen BTC können verloren gehen. Erstellen Sie eine neue 24-Wort-Wallet (tippen Sie auf das Menü oben rechts, wählen Sie Wallets, wählen Sie Neue Wallet erstellen und dann Bitcoin) und verschieben Sie Ihre BTC SOFORT dorthin. Neue (24-Wort-)BTC-Wallets von Cake sind sicher",
"outgoing": "Ausgehend", "outgoing": "Ausgehend",
"outputs": "Ausgänge",
"overwrite_amount": "Overwrite amount", "overwrite_amount": "Overwrite amount",
"pairingInvalidEvent": "Paarung ungültiges Ereignis", "pairingInvalidEvent": "Paarung ungültiges Ereignis",
"password": "Passwort", "password": "Passwort",
@ -422,8 +434,8 @@
"placeholder_transactions": "Ihre Transaktionen werden hier angezeigt", "placeholder_transactions": "Ihre Transaktionen werden hier angezeigt",
"please_fill_totp": "Bitte geben Sie den 8-stelligen Code ein, der auf Ihrem anderen Gerät vorhanden ist", "please_fill_totp": "Bitte geben Sie den 8-stelligen Code ein, der auf Ihrem anderen Gerät vorhanden ist",
"please_make_selection": "Bitte treffen Sie unten eine Auswahl zum Erstellen oder Wiederherstellen Ihrer Wallet.", "please_make_selection": "Bitte treffen Sie unten eine Auswahl zum Erstellen oder Wiederherstellen Ihrer Wallet.",
"please_reference_document": "Bitte verweisen Sie auf die folgenden Dokumente, um weitere Informationen zu erhalten.",
"Please_reference_document": "Weitere Informationen finden Sie in den Dokumenten unten.", "Please_reference_document": "Weitere Informationen finden Sie in den Dokumenten unten.",
"please_reference_document": "Bitte verweisen Sie auf die folgenden Dokumente, um weitere Informationen zu erhalten.",
"please_select": "Bitte auswählen:", "please_select": "Bitte auswählen:",
"please_select_backup_file": "Bitte wählen Sie die Sicherungsdatei und geben Sie das Sicherungskennwort ein.", "please_select_backup_file": "Bitte wählen Sie die Sicherungsdatei und geben Sie das Sicherungskennwort ein.",
"please_try_to_connect_to_another_node": "Bitte versuchen Sie, sich mit einem anderen Knoten zu verbinden", "please_try_to_connect_to_another_node": "Bitte versuchen Sie, sich mit einem anderen Knoten zu verbinden",
@ -465,6 +477,8 @@
"remove_node": "Knoten entfernen", "remove_node": "Knoten entfernen",
"remove_node_message": "Möchten Sie den ausgewählten Knoten wirklich entfernen?", "remove_node_message": "Möchten Sie den ausgewählten Knoten wirklich entfernen?",
"rename": "Umbenennen", "rename": "Umbenennen",
"rep_warning": "Repräsentative Warnung",
"rep_warning_sub": "Ihr Vertreter scheint nicht gut zu sein. Tippen Sie hier, um eine neue auszuwählen",
"require_for_adding_contacts": "Erforderlich zum Hinzufügen von Kontakten", "require_for_adding_contacts": "Erforderlich zum Hinzufügen von Kontakten",
"require_for_all_security_and_backup_settings": "Für alle Sicherheits- und Sicherungseinstellungen erforderlich", "require_for_all_security_and_backup_settings": "Für alle Sicherheits- und Sicherungseinstellungen erforderlich",
"require_for_assessing_wallet": "Für den Zugriff auf die Wallet erforderlich", "require_for_assessing_wallet": "Für den Zugriff auf die Wallet erforderlich",
@ -743,6 +757,7 @@
"unspent_coins_details_title": "Details zu nicht ausgegebenen Coins", "unspent_coins_details_title": "Details zu nicht ausgegebenen Coins",
"unspent_coins_title": "Nicht ausgegebene Coins", "unspent_coins_title": "Nicht ausgegebene Coins",
"unsupported_asset": "Wir unterstützen diese Aktion für dieses Asset nicht. Bitte erstellen Sie eine Wallet eines unterstützten Asset-Typs oder wechseln Sie zu einer Wallet.", "unsupported_asset": "Wir unterstützen diese Aktion für dieses Asset nicht. Bitte erstellen Sie eine Wallet eines unterstützten Asset-Typs oder wechseln Sie zu einer Wallet.",
"uptime": "Betriebszeit",
"upto": "bis zu ${value}", "upto": "bis zu ${value}",
"use": "Wechsel zu ", "use": "Wechsel zu ",
"use_card_info_three": "Verwenden Sie die digitale Karte online oder mit kontaktlosen Zahlungsmethoden.", "use_card_info_three": "Verwenden Sie die digitale Karte online oder mit kontaktlosen Zahlungsmethoden.",
@ -759,6 +774,7 @@
"view_key_private": "View Key (geheim)", "view_key_private": "View Key (geheim)",
"view_key_public": "View Key (öffentlich)", "view_key_public": "View Key (öffentlich)",
"view_transaction_on": "Anzeigen der Transaktion auf ", "view_transaction_on": "Anzeigen der Transaktion auf ",
"voting_weight": "Stimmgewicht",
"waitFewSecondForTxUpdate": "Bitte warten Sie einige Sekunden, bis die Transaktion im Transaktionsverlauf angezeigt wird", "waitFewSecondForTxUpdate": "Bitte warten Sie einige Sekunden, bis die Transaktion im Transaktionsverlauf angezeigt wird",
"waiting_payment_confirmation": "Warte auf Zahlungsbestätigung", "waiting_payment_confirmation": "Warte auf Zahlungsbestätigung",
"wallet_keys": "Wallet-Seed/-Schlüssel", "wallet_keys": "Wallet-Seed/-Schlüssel",

View file

@ -59,6 +59,7 @@
"auth_store_incorrect_password": "Wrong PIN", "auth_store_incorrect_password": "Wrong PIN",
"authenticated": "Authenticated", "authenticated": "Authenticated",
"authentication": "Authentication", "authentication": "Authentication",
"auto_generate_addresses": "Auto generate addresses",
"auto_generate_subaddresses": "Auto generate subaddresses", "auto_generate_subaddresses": "Auto generate subaddresses",
"automatic": "Automatic", "automatic": "Automatic",
"available_balance": "Available Balance", "available_balance": "Available Balance",
@ -81,6 +82,7 @@
"breez_warning_disruption": "The breez service is currently experiencing issues. Please try again later.", "breez_warning_disruption": "The breez service is currently experiencing issues. Please try again later.",
"breez_warning_maintenance": "The breez service is currently undergoing maintenance. Please try again later.", "breez_warning_maintenance": "The breez service is currently undergoing maintenance. Please try again later.",
"bright_theme": "Bright", "bright_theme": "Bright",
"bump_fee": "Bump fee",
"buy": "Buy", "buy": "Buy",
"buy_alert_content": "Currently we only support the purchase of Bitcoin, Ethereum, Litecoin, and Monero. Please create or switch to your Bitcoin, Ethereum, Litecoin, or Monero wallet.", "buy_alert_content": "Currently we only support the purchase of Bitcoin, Ethereum, Litecoin, and Monero. Please create or switch to your Bitcoin, Ethereum, Litecoin, or Monero wallet.",
"buy_bitcoin": "Buy Bitcoin", "buy_bitcoin": "Buy Bitcoin",
@ -135,6 +137,8 @@
"confirm": "Confirm", "confirm": "Confirm",
"confirm_delete_template": "This action will delete this template. Do you wish to continue?", "confirm_delete_template": "This action will delete this template. Do you wish to continue?",
"confirm_delete_wallet": "This action will delete this wallet. Do you wish to continue?", "confirm_delete_wallet": "This action will delete this wallet. Do you wish to continue?",
"confirm_fee_deduction": "Confirm Fee Deduction",
"confirm_fee_deduction_content": "Do you agree to deduct the fee from the output?",
"confirm_sending": "Confirm sending", "confirm_sending": "Confirm sending",
"confirmations": "Confirmations", "confirmations": "Confirmations",
"confirmed": "Confirmed Balance", "confirmed": "Confirmed Balance",
@ -174,6 +178,7 @@
"debit_card": "Debit Card", "debit_card": "Debit Card",
"debit_card_terms": "The storage and usage of your payment card number (and credentials corresponding to your payment card number) in this digital wallet are subject to the Terms and Conditions of the applicable cardholder agreement with the payment card issuer, as in effect from time to time.", "debit_card_terms": "The storage and usage of your payment card number (and credentials corresponding to your payment card number) in this digital wallet are subject to the Terms and Conditions of the applicable cardholder agreement with the payment card issuer, as in effect from time to time.",
"decimal_places_error": "Too many decimal places", "decimal_places_error": "Too many decimal places",
"decimals_cannot_be_zero": "Token decimal cannot be zero.",
"default_buy_provider": "Default Buy Provider", "default_buy_provider": "Default Buy Provider",
"default_sell_provider": "Default Sell Provider", "default_sell_provider": "Default Sell Provider",
"delete": "Delete", "delete": "Delete",
@ -214,6 +219,7 @@
"edit_token": "Edit token", "edit_token": "Edit token",
"electrum_address_disclaimer": "We generate new addresses each time you use one, but previous addresses continue to work", "electrum_address_disclaimer": "We generate new addresses each time you use one, but previous addresses continue to work",
"email_address": "Email Address", "email_address": "Email Address",
"enable_replace_by_fee": "Enable Replace-By-Fee",
"enabled": "Enabled", "enabled": "Enabled",
"enter_amount": "Enter Amount", "enter_amount": "Enter Amount",
"enter_backup_password": "Enter backup password here", "enter_backup_password": "Enter backup password here",
@ -250,6 +256,7 @@
"errorGettingCredentials": "Failed: Error while getting credentials", "errorGettingCredentials": "Failed: Error while getting credentials",
"errorSigningTransaction": "An error has occured while signing transaction", "errorSigningTransaction": "An error has occured while signing transaction",
"estimated": "Estimated", "estimated": "Estimated",
"estimated_new_fee": "Estimated new fee",
"etherscan_history": "Etherscan history", "etherscan_history": "Etherscan history",
"event": "Event", "event": "Event",
"events": "Events", "events": "Events",
@ -316,6 +323,7 @@
"in_store": "In Store", "in_store": "In Store",
"incoming": "Incoming", "incoming": "Incoming",
"incorrect_seed": "The text entered is not valid.", "incorrect_seed": "The text entered is not valid.",
"inputs": "Inputs",
"introducing_cake_pay": "Introducing Cake Pay!", "introducing_cake_pay": "Introducing Cake Pay!",
"invalid_input": "Invalid input", "invalid_input": "Invalid input",
"invoice": "Invoice", "invoice": "Invoice",
@ -358,6 +366,8 @@
"moonpay_alert_text": "Value of the amount must be more or equal to ${minAmount} ${fiatCurrency}", "moonpay_alert_text": "Value of the amount must be more or equal to ${minAmount} ${fiatCurrency}",
"more_options": "More Options", "more_options": "More Options",
"name": "Name", "name": "Name",
"nano_current_rep": "Current Representative",
"nano_pick_new_rep": "Pick a new representative",
"narrow": "Narrow", "narrow": "Narrow",
"new_first_wallet_text": "Keep your crypto safe, piece of cake", "new_first_wallet_text": "Keep your crypto safe, piece of cake",
"new_node_testing": "New node testing", "new_node_testing": "New node testing",
@ -390,6 +400,7 @@
"offer_expires_in": "Offer expires in: ", "offer_expires_in": "Offer expires in: ",
"offline": "Offline", "offline": "Offline",
"ok": "OK", "ok": "OK",
"old_fee": "Old fee",
"onion_link": "Onion link", "onion_link": "Onion link",
"online": "Online", "online": "Online",
"onramper_option_description": "Quickly buy crypto with many payment methods. Available in most countries. Spreads and fees vary.", "onramper_option_description": "Quickly buy crypto with many payment methods. Available in most countries. Spreads and fees vary.",
@ -406,6 +417,7 @@
"outdated_electrum_wallet_description": "New Bitcoin wallets created in Cake now have a 24-word seed. It is mandatory that you create a new Bitcoin wallet and transfer all of your funds to the new 24-word wallet, and stop using wallets with a 12-word seed. Please do this immediately to secure your funds.", "outdated_electrum_wallet_description": "New Bitcoin wallets created in Cake now have a 24-word seed. It is mandatory that you create a new Bitcoin wallet and transfer all of your funds to the new 24-word wallet, and stop using wallets with a 12-word seed. Please do this immediately to secure your funds.",
"outdated_electrum_wallet_receive_warning": "If this wallet has a 12-word seed and was created in Cake, DO NOT deposit Bitcoin into this wallet. Any BTC transferred to this wallet may be lost. Create a new 24-word wallet (tap the menu at the top right, select Wallets, choose Create New Wallet, then select Bitcoin) and IMMEDIATELY move your BTC there. New (24-word) BTC wallets from Cake are secure", "outdated_electrum_wallet_receive_warning": "If this wallet has a 12-word seed and was created in Cake, DO NOT deposit Bitcoin into this wallet. Any BTC transferred to this wallet may be lost. Create a new 24-word wallet (tap the menu at the top right, select Wallets, choose Create New Wallet, then select Bitcoin) and IMMEDIATELY move your BTC there. New (24-word) BTC wallets from Cake are secure",
"outgoing": "Outgoing", "outgoing": "Outgoing",
"outputs": "Outputs",
"overwrite_amount": "Overwrite amount", "overwrite_amount": "Overwrite amount",
"pairingInvalidEvent": "Pairing Invalid Event", "pairingInvalidEvent": "Pairing Invalid Event",
"password": "Password", "password": "Password",
@ -464,6 +476,8 @@
"remove_node": "Remove node", "remove_node": "Remove node",
"remove_node_message": "Are you sure that you want to remove selected node?", "remove_node_message": "Are you sure that you want to remove selected node?",
"rename": "Rename", "rename": "Rename",
"rep_warning": "Representative Warning",
"rep_warning_sub": "Your representative does not appear to be in good standing. Tap here to select a new one",
"require_for_adding_contacts": "Require for adding contacts", "require_for_adding_contacts": "Require for adding contacts",
"require_for_all_security_and_backup_settings": "Require for all security and backup settings", "require_for_all_security_and_backup_settings": "Require for all security and backup settings",
"require_for_assessing_wallet": "Require for accessing wallet", "require_for_assessing_wallet": "Require for accessing wallet",
@ -741,6 +755,7 @@
"unspent_coins_details_title": "Unspent coins details", "unspent_coins_details_title": "Unspent coins details",
"unspent_coins_title": "Unspent coins", "unspent_coins_title": "Unspent coins",
"unsupported_asset": "We don't support this action for this asset. Please create or switch to a wallet of a supported asset type.", "unsupported_asset": "We don't support this action for this asset. Please create or switch to a wallet of a supported asset type.",
"uptime": "Uptime",
"upto": "up to ${value}", "upto": "up to ${value}",
"use": "Switch to ", "use": "Switch to ",
"use_card_info_three": "Use the digital card online or with contactless payment methods.", "use_card_info_three": "Use the digital card online or with contactless payment methods.",
@ -757,6 +772,7 @@
"view_key_private": "View key (private)", "view_key_private": "View key (private)",
"view_key_public": "View key (public)", "view_key_public": "View key (public)",
"view_transaction_on": "View Transaction on ", "view_transaction_on": "View Transaction on ",
"voting_weight": "Voting Weight",
"waitFewSecondForTxUpdate": "Kindly wait for a few seconds for transaction to reflect in transactions history", "waitFewSecondForTxUpdate": "Kindly wait for a few seconds for transaction to reflect in transactions history",
"wallet_keys": "Wallet seed/keys", "wallet_keys": "Wallet seed/keys",
"wallet_list_create_new_wallet": "Create New Wallet", "wallet_list_create_new_wallet": "Create New Wallet",

View file

@ -59,6 +59,7 @@
"auth_store_incorrect_password": "Contraseña PIN", "auth_store_incorrect_password": "Contraseña PIN",
"authenticated": "Autenticados", "authenticated": "Autenticados",
"authentication": "Autenticación", "authentication": "Autenticación",
"auto_generate_addresses": "Auto Generar direcciones",
"auto_generate_subaddresses": "Generar subdirecciones automáticamente", "auto_generate_subaddresses": "Generar subdirecciones automáticamente",
"automatic": "Automático", "automatic": "Automático",
"available_balance": "Balance disponible", "available_balance": "Balance disponible",
@ -81,6 +82,7 @@
"breez_warning_disruption": "El servicio Breez está experimentando problemas. Por favor, inténtelo de nuevo más tarde.", "breez_warning_disruption": "El servicio Breez está experimentando problemas. Por favor, inténtelo de nuevo más tarde.",
"breez_warning_maintenance": "El servicio Breez está actualmente en mantenimiento. Por favor, inténtelo de nuevo más tarde.", "breez_warning_maintenance": "El servicio Breez está actualmente en mantenimiento. Por favor, inténtelo de nuevo más tarde.",
"bright_theme": "Brillante", "bright_theme": "Brillante",
"bump_fee": "Tarifa",
"buy": "Comprar", "buy": "Comprar",
"buy_alert_content": "Actualmente solo admitimos la compra de Bitcoin, Ethereum, Litecoin y Monero. Cree o cambie a su billetera Bitcoin, Ethereum, Litecoin o Monero.", "buy_alert_content": "Actualmente solo admitimos la compra de Bitcoin, Ethereum, Litecoin y Monero. Cree o cambie a su billetera Bitcoin, Ethereum, Litecoin o Monero.",
"buy_bitcoin": "Comprar Bitcoin", "buy_bitcoin": "Comprar Bitcoin",
@ -135,6 +137,8 @@
"confirm": "Confirmar", "confirm": "Confirmar",
"confirm_delete_template": "Esta acción eliminará esta plantilla. ¿Desea continuar?", "confirm_delete_template": "Esta acción eliminará esta plantilla. ¿Desea continuar?",
"confirm_delete_wallet": "Esta acción eliminará esta billetera. ¿Desea continuar?", "confirm_delete_wallet": "Esta acción eliminará esta billetera. ¿Desea continuar?",
"confirm_fee_deduction": "Confirmar la deducción de la tarifa",
"confirm_fee_deduction_content": "¿Acepta deducir la tarifa de la producción?",
"confirm_sending": "Confirmar envío", "confirm_sending": "Confirmar envío",
"confirmations": "Confirmaciones", "confirmations": "Confirmaciones",
"confirmed": "Saldo confirmado", "confirmed": "Saldo confirmado",
@ -174,6 +178,7 @@
"debit_card": "Tarjeta de Débito", "debit_card": "Tarjeta de Débito",
"debit_card_terms": "El almacenamiento y el uso de su número de tarjeta de pago (y las credenciales correspondientes a su número de tarjeta de pago) en esta billetera digital están sujetos a los Términos y condiciones del acuerdo del titular de la tarjeta aplicable con el emisor de la tarjeta de pago, en vigor desde tiempo al tiempo.", "debit_card_terms": "El almacenamiento y el uso de su número de tarjeta de pago (y las credenciales correspondientes a su número de tarjeta de pago) en esta billetera digital están sujetos a los Términos y condiciones del acuerdo del titular de la tarjeta aplicable con el emisor de la tarjeta de pago, en vigor desde tiempo al tiempo.",
"decimal_places_error": "Demasiados lugares decimales", "decimal_places_error": "Demasiados lugares decimales",
"decimals_cannot_be_zero": "Token Decimal no puede ser cero.",
"default_buy_provider": "Proveedor de compra predeterminado", "default_buy_provider": "Proveedor de compra predeterminado",
"default_sell_provider": "Proveedor de venta predeterminado", "default_sell_provider": "Proveedor de venta predeterminado",
"delete": "Borrar", "delete": "Borrar",
@ -214,6 +219,7 @@
"edit_token": "Editar token", "edit_token": "Editar token",
"electrum_address_disclaimer": "Generamos nuevas direcciones cada vez que usa una, pero las direcciones anteriores siguen funcionando", "electrum_address_disclaimer": "Generamos nuevas direcciones cada vez que usa una, pero las direcciones anteriores siguen funcionando",
"email_address": "Dirección de correo electrónico", "email_address": "Dirección de correo electrónico",
"enable_replace_by_fee": "Habilitar reemplazar por tarea",
"enabled": "Activado", "enabled": "Activado",
"enter_amount": "Ingrese la cantidad", "enter_amount": "Ingrese la cantidad",
"enter_backup_password": "Ingrese la contraseña de respaldo aquí", "enter_backup_password": "Ingrese la contraseña de respaldo aquí",
@ -250,6 +256,7 @@
"errorGettingCredentials": "Error: error al obtener las credenciales", "errorGettingCredentials": "Error: error al obtener las credenciales",
"errorSigningTransaction": "Se ha producido un error al firmar la transacción.", "errorSigningTransaction": "Se ha producido un error al firmar la transacción.",
"estimated": "Estimado", "estimated": "Estimado",
"estimated_new_fee": "Nueva tarifa estimada",
"etherscan_history": "historia de etherscan", "etherscan_history": "historia de etherscan",
"event": "Evento", "event": "Evento",
"events": "Eventos", "events": "Eventos",
@ -316,6 +323,7 @@
"in_store": "En la tienda", "in_store": "En la tienda",
"incoming": "Entrante", "incoming": "Entrante",
"incorrect_seed": "El texto ingresado no es válido.", "incorrect_seed": "El texto ingresado no es válido.",
"inputs": "Entradas",
"introducing_cake_pay": "¡Presentamos Cake Pay!", "introducing_cake_pay": "¡Presentamos Cake Pay!",
"invalid_input": "Entrada inválida", "invalid_input": "Entrada inválida",
"invoice": "Factura", "invoice": "Factura",
@ -358,6 +366,8 @@
"moonpay_alert_text": "El valor de la cantidad debe ser mayor o igual a ${minAmount} ${fiatCurrency}", "moonpay_alert_text": "El valor de la cantidad debe ser mayor o igual a ${minAmount} ${fiatCurrency}",
"more_options": "Más Opciones", "more_options": "Más Opciones",
"name": "Nombre", "name": "Nombre",
"nano_current_rep": "Representante actual",
"nano_pick_new_rep": "Elija un nuevo representante",
"narrow": "Angosto", "narrow": "Angosto",
"new_first_wallet_text": "Mantenga fácilmente su criptomoneda segura", "new_first_wallet_text": "Mantenga fácilmente su criptomoneda segura",
"new_node_testing": "Prueba de nuevos nodos", "new_node_testing": "Prueba de nuevos nodos",
@ -390,6 +400,7 @@
"offer_expires_in": "Oferta expira en: ", "offer_expires_in": "Oferta expira en: ",
"offline": "fuera de línea", "offline": "fuera de línea",
"ok": "OK", "ok": "OK",
"old_fee": "Tarifa antigua",
"onion_link": "Enlace de cebolla", "onion_link": "Enlace de cebolla",
"online": "En línea", "online": "En línea",
"onramper_option_description": "Compre rápidamente cripto con muchos métodos de pago. Disponible en la mayoría de los países. Los diferenciales y las tarifas varían.", "onramper_option_description": "Compre rápidamente cripto con muchos métodos de pago. Disponible en la mayoría de los países. Los diferenciales y las tarifas varían.",
@ -406,6 +417,7 @@
"outdated_electrum_wallet_description": "Las nuevas carteras de Bitcoin creadas en Cake ahora tienen una semilla de 24 palabras. Es obligatorio que cree una nueva billetera de Bitcoin y transfiera todos sus fondos a la nueva billetera de 24 palabras, y deje de usar billeteras con una semilla de 12 palabras. Haga esto de inmediato para asegurar sus fondos.", "outdated_electrum_wallet_description": "Las nuevas carteras de Bitcoin creadas en Cake ahora tienen una semilla de 24 palabras. Es obligatorio que cree una nueva billetera de Bitcoin y transfiera todos sus fondos a la nueva billetera de 24 palabras, y deje de usar billeteras con una semilla de 12 palabras. Haga esto de inmediato para asegurar sus fondos.",
"outdated_electrum_wallet_receive_warning": "Si esta billetera tiene una semilla de 12 palabras y se creó en Cake, NO deposite Bitcoin en esta billetera. Cualquier BTC transferido a esta billetera se puede perder. Cree una nueva billetera de 24 palabras (toque el menú en la parte superior derecha, seleccione Monederos, elija Crear nueva billetera, luego seleccione Bitcoin) e INMEDIATAMENTE mueva su BTC allí. Las nuevas carteras BTC (24 palabras) de Cake son seguras", "outdated_electrum_wallet_receive_warning": "Si esta billetera tiene una semilla de 12 palabras y se creó en Cake, NO deposite Bitcoin en esta billetera. Cualquier BTC transferido a esta billetera se puede perder. Cree una nueva billetera de 24 palabras (toque el menú en la parte superior derecha, seleccione Monederos, elija Crear nueva billetera, luego seleccione Bitcoin) e INMEDIATAMENTE mueva su BTC allí. Las nuevas carteras BTC (24 palabras) de Cake son seguras",
"outgoing": "Saliente", "outgoing": "Saliente",
"outputs": "Salidas",
"overwrite_amount": "Overwrite amount", "overwrite_amount": "Overwrite amount",
"pairingInvalidEvent": "Evento de emparejamiento no válido", "pairingInvalidEvent": "Evento de emparejamiento no válido",
"password": "Contraseña", "password": "Contraseña",
@ -465,6 +477,8 @@
"remove_node": "Eliminar nodo", "remove_node": "Eliminar nodo",
"remove_node_message": "¿Está seguro de que desea eliminar el nodo seleccionado?", "remove_node_message": "¿Está seguro de que desea eliminar el nodo seleccionado?",
"rename": "Rebautizar", "rename": "Rebautizar",
"rep_warning": "Advertencia representativa",
"rep_warning_sub": "Su representante no parece estar en buena posición. Toque aquí para seleccionar uno nuevo",
"require_for_adding_contacts": "Requerido para agregar contactos", "require_for_adding_contacts": "Requerido para agregar contactos",
"require_for_all_security_and_backup_settings": "Requerido para todas las configuraciones de seguridad y copia de seguridad", "require_for_all_security_and_backup_settings": "Requerido para todas las configuraciones de seguridad y copia de seguridad",
"require_for_assessing_wallet": "Requerido para acceder a la billetera", "require_for_assessing_wallet": "Requerido para acceder a la billetera",
@ -742,6 +756,7 @@
"unspent_coins_details_title": "Detalles de monedas no gastadas", "unspent_coins_details_title": "Detalles de monedas no gastadas",
"unspent_coins_title": "Monedas no gastadas", "unspent_coins_title": "Monedas no gastadas",
"unsupported_asset": "No admitimos esta acción para este activo. Cree o cambie a una billetera de un tipo de activo admitido.", "unsupported_asset": "No admitimos esta acción para este activo. Cree o cambie a una billetera de un tipo de activo admitido.",
"uptime": "Tiempo de actividad",
"upto": "hasta ${value}", "upto": "hasta ${value}",
"use": "Utilizar a ", "use": "Utilizar a ",
"use_card_info_three": "Utilice la tarjeta digital en línea o con métodos de pago sin contacto.", "use_card_info_three": "Utilice la tarjeta digital en línea o con métodos de pago sin contacto.",
@ -758,6 +773,7 @@
"view_key_private": "View clave (privado)", "view_key_private": "View clave (privado)",
"view_key_public": "View clave (público)", "view_key_public": "View clave (público)",
"view_transaction_on": "View Transaction on ", "view_transaction_on": "View Transaction on ",
"voting_weight": "Peso de votación",
"waitFewSecondForTxUpdate": "Espere unos segundos para que la transacción se refleje en el historial de transacciones.", "waitFewSecondForTxUpdate": "Espere unos segundos para que la transacción se refleje en el historial de transacciones.",
"wallet_keys": "Billetera semilla/claves", "wallet_keys": "Billetera semilla/claves",
"wallet_list_create_new_wallet": "Crear nueva billetera", "wallet_list_create_new_wallet": "Crear nueva billetera",

View file

@ -59,6 +59,7 @@
"auth_store_incorrect_password": "Mauvais code PIN", "auth_store_incorrect_password": "Mauvais code PIN",
"authenticated": "Authentifié", "authenticated": "Authentifié",
"authentication": "Authentification", "authentication": "Authentification",
"auto_generate_addresses": "Adresses de génération automatique",
"auto_generate_subaddresses": "Générer automatiquement des sous-adresses", "auto_generate_subaddresses": "Générer automatiquement des sous-adresses",
"automatic": "Automatique", "automatic": "Automatique",
"available_balance": "Solde Disponible", "available_balance": "Solde Disponible",
@ -81,6 +82,7 @@
"breez_warning_disruption": "Le service Breez connaît actuellement des problèmes. Veuillez réessayer plus tard.", "breez_warning_disruption": "Le service Breez connaît actuellement des problèmes. Veuillez réessayer plus tard.",
"breez_warning_maintenance": "Le service Breez est actuellement en maintenance. Veuillez réessayer plus tard.", "breez_warning_maintenance": "Le service Breez est actuellement en maintenance. Veuillez réessayer plus tard.",
"bright_theme": "Vif", "bright_theme": "Vif",
"bump_fee": "Frais de bosse",
"buy": "Acheter", "buy": "Acheter",
"buy_alert_content": "Actuellement, nous ne prenons en charge que l'achat de Bitcoin, Ethereum, Litecoin et Monero. Veuillez créer ou basculer vers votre portefeuille Bitcoin, Ethereum, Litecoin ou Monero.", "buy_alert_content": "Actuellement, nous ne prenons en charge que l'achat de Bitcoin, Ethereum, Litecoin et Monero. Veuillez créer ou basculer vers votre portefeuille Bitcoin, Ethereum, Litecoin ou Monero.",
"buy_bitcoin": "Acheter du Bitcoin", "buy_bitcoin": "Acheter du Bitcoin",
@ -135,6 +137,8 @@
"confirm": "Confirmer", "confirm": "Confirmer",
"confirm_delete_template": "Cette action va supprimer ce modèle. Souhaitez-vous continuer ?", "confirm_delete_template": "Cette action va supprimer ce modèle. Souhaitez-vous continuer ?",
"confirm_delete_wallet": "Cette action va supprimer ce portefeuille (wallet). Souhaitez-vous contnuer ?", "confirm_delete_wallet": "Cette action va supprimer ce portefeuille (wallet). Souhaitez-vous contnuer ?",
"confirm_fee_deduction": "Confirmer la déduction des frais",
"confirm_fee_deduction_content": "Acceptez-vous de déduire les frais de la production?",
"confirm_sending": "Confirmer l'envoi", "confirm_sending": "Confirmer l'envoi",
"confirmations": "Confirmations", "confirmations": "Confirmations",
"confirmed": "Solde confirmé", "confirmed": "Solde confirmé",
@ -174,6 +178,7 @@
"debit_card": "Carte de débit", "debit_card": "Carte de débit",
"debit_card_terms": "Le stockage et l'utilisation de votre numéro de carte de paiement (et des informations d'identification correspondant à votre numéro de carte de paiement) dans ce portefeuille (wallet) numérique peuvent être soumis aux conditions générales de l'accord du titulaire de carte parfois en vigueur avec l'émetteur de la carte de paiement.", "debit_card_terms": "Le stockage et l'utilisation de votre numéro de carte de paiement (et des informations d'identification correspondant à votre numéro de carte de paiement) dans ce portefeuille (wallet) numérique peuvent être soumis aux conditions générales de l'accord du titulaire de carte parfois en vigueur avec l'émetteur de la carte de paiement.",
"decimal_places_error": "Trop de décimales", "decimal_places_error": "Trop de décimales",
"decimals_cannot_be_zero": "La décimale du jeton ne peut pas être nulle.",
"default_buy_provider": "Fournisseur d'achat par défaut", "default_buy_provider": "Fournisseur d'achat par défaut",
"default_sell_provider": "Fournisseur de vente par défaut", "default_sell_provider": "Fournisseur de vente par défaut",
"delete": "Effacer", "delete": "Effacer",
@ -214,6 +219,7 @@
"edit_token": "Modifier le token", "edit_token": "Modifier le token",
"electrum_address_disclaimer": "Nous générons de nouvelles adresses à chaque fois que vous en utilisez une, mais les adresses précédentes continuent à fonctionner", "electrum_address_disclaimer": "Nous générons de nouvelles adresses à chaque fois que vous en utilisez une, mais les adresses précédentes continuent à fonctionner",
"email_address": "Adresse e-mail", "email_address": "Adresse e-mail",
"enable_replace_by_fee": "Activer Remplace-by-Fee",
"enabled": "Activé", "enabled": "Activé",
"enter_amount": "Entrez le montant", "enter_amount": "Entrez le montant",
"enter_backup_password": "Entrez le mot de passe de sauvegarde ici", "enter_backup_password": "Entrez le mot de passe de sauvegarde ici",
@ -250,6 +256,7 @@
"errorGettingCredentials": "Échec : erreur lors de l'obtention des informations d'identification", "errorGettingCredentials": "Échec : erreur lors de l'obtention des informations d'identification",
"errorSigningTransaction": "Une erreur s'est produite lors de la signature de la transaction", "errorSigningTransaction": "Une erreur s'est produite lors de la signature de la transaction",
"estimated": "Estimé", "estimated": "Estimé",
"estimated_new_fee": "De nouveaux frais estimés",
"etherscan_history": "Historique d'Etherscan", "etherscan_history": "Historique d'Etherscan",
"event": "Événement", "event": "Événement",
"events": "Événements", "events": "Événements",
@ -316,6 +323,7 @@
"in_store": "En magasin", "in_store": "En magasin",
"incoming": "Entrantes", "incoming": "Entrantes",
"incorrect_seed": "Le texte entré est invalide.", "incorrect_seed": "Le texte entré est invalide.",
"inputs": "Contributions",
"introducing_cake_pay": "Présentation de Cake Pay !", "introducing_cake_pay": "Présentation de Cake Pay !",
"invalid_input": "Entrée invalide", "invalid_input": "Entrée invalide",
"invoice": "Facture", "invoice": "Facture",
@ -358,6 +366,8 @@
"moonpay_alert_text": "Le montant doit être au moins égal à ${minAmount} ${fiatCurrency}", "moonpay_alert_text": "Le montant doit être au moins égal à ${minAmount} ${fiatCurrency}",
"more_options": "Plus d'options", "more_options": "Plus d'options",
"name": "Nom", "name": "Nom",
"nano_current_rep": "Représentant actuel",
"nano_pick_new_rep": "Choisissez un nouveau représentant",
"narrow": "Étroit", "narrow": "Étroit",
"new_first_wallet_text": "Gardez facilement votre crypto-monnaie en sécurité", "new_first_wallet_text": "Gardez facilement votre crypto-monnaie en sécurité",
"new_node_testing": "Test du nouveau nœud", "new_node_testing": "Test du nouveau nœud",
@ -390,6 +400,7 @@
"offer_expires_in": "L'Offre expire dans : ", "offer_expires_in": "L'Offre expire dans : ",
"offline": "Hors ligne", "offline": "Hors ligne",
"ok": "OK", "ok": "OK",
"old_fee": "Anciens",
"onion_link": "Lien .onion", "onion_link": "Lien .onion",
"online": "En ligne", "online": "En ligne",
"onramper_option_description": "Achetez rapidement des cryptomonnaies avec de nombreuses méthodes de paiement. Disponible dans la plupart des pays. Les spreads et les frais peuvent varier.", "onramper_option_description": "Achetez rapidement des cryptomonnaies avec de nombreuses méthodes de paiement. Disponible dans la plupart des pays. Les spreads et les frais peuvent varier.",
@ -406,6 +417,7 @@
"outdated_electrum_wallet_description": "Les nouveaux portefeuilles (wallets) Bitcoin créés dans Cake ont dorénavant une phrase secrète (seed) de 24 mots. Il est impératif que vous créiez un nouveau portefeuille Bitcoin, que vous y transfériez tous vos fonds puis que vous cessiez d'utiliser le portefeuille avec une phrase secrète de 12 mots. Merci de faire cela immédiatement pour assurer la sécurité de vos avoirs.", "outdated_electrum_wallet_description": "Les nouveaux portefeuilles (wallets) Bitcoin créés dans Cake ont dorénavant une phrase secrète (seed) de 24 mots. Il est impératif que vous créiez un nouveau portefeuille Bitcoin, que vous y transfériez tous vos fonds puis que vous cessiez d'utiliser le portefeuille avec une phrase secrète de 12 mots. Merci de faire cela immédiatement pour assurer la sécurité de vos avoirs.",
"outdated_electrum_wallet_receive_warning": "Si ce portefeuille (wallet) a une phrase secrète (seed) de 12 mots et a été créé dans Cake, NE PAS y déposer de Bitcoin. Tous les BTC transférés vers ce portefeuille seront perdus. Créez un nouveau portefeuille avec phrase secrète de 24 mots (appuyez sur le menu en haut à droite, sélectionnez Portefeuilles puis Créer un Nouveau Portefeuille et enfin Bitcoin) et transférez y IMMÉDIATEMENT vos BTC. Les nouveaux portefeuilles BTC Cake (avec phrase secrète de 24 mots) sont sécurisés", "outdated_electrum_wallet_receive_warning": "Si ce portefeuille (wallet) a une phrase secrète (seed) de 12 mots et a été créé dans Cake, NE PAS y déposer de Bitcoin. Tous les BTC transférés vers ce portefeuille seront perdus. Créez un nouveau portefeuille avec phrase secrète de 24 mots (appuyez sur le menu en haut à droite, sélectionnez Portefeuilles puis Créer un Nouveau Portefeuille et enfin Bitcoin) et transférez y IMMÉDIATEMENT vos BTC. Les nouveaux portefeuilles BTC Cake (avec phrase secrète de 24 mots) sont sécurisés",
"outgoing": "Sortantes", "outgoing": "Sortantes",
"outputs": "Les sorties",
"overwrite_amount": "Remplacer le montant", "overwrite_amount": "Remplacer le montant",
"pairingInvalidEvent": "Événement de couplage non valide", "pairingInvalidEvent": "Événement de couplage non valide",
"password": "Mot de passe", "password": "Mot de passe",
@ -464,6 +476,8 @@
"remove_node": "Supprimer le nœud", "remove_node": "Supprimer le nœud",
"remove_node_message": "Êtes vous certain de vouloir supprimer le nœud sélectionné ?", "remove_node_message": "Êtes vous certain de vouloir supprimer le nœud sélectionné ?",
"rename": "Renommer", "rename": "Renommer",
"rep_warning": "Avertissement représentatif",
"rep_warning_sub": "Votre représentant ne semble pas être en règle. Appuyez ici pour en sélectionner un nouveau",
"require_for_adding_contacts": "Requis pour ajouter des contacts", "require_for_adding_contacts": "Requis pour ajouter des contacts",
"require_for_all_security_and_backup_settings": "Exiger pour tous les paramètres de sécurité et de sauvegarde", "require_for_all_security_and_backup_settings": "Exiger pour tous les paramètres de sécurité et de sauvegarde",
"require_for_assessing_wallet": "Nécessaire pour accéder au portefeuille", "require_for_assessing_wallet": "Nécessaire pour accéder au portefeuille",
@ -741,6 +755,7 @@
"unspent_coins_details_title": "Détails des pièces (coins) non dépensées", "unspent_coins_details_title": "Détails des pièces (coins) non dépensées",
"unspent_coins_title": "Pièces (coins) non dépensées", "unspent_coins_title": "Pièces (coins) non dépensées",
"unsupported_asset": "Nous ne prenons pas en charge cette action pour cet élément. Veuillez créer ou passer à un portefeuille d'un type d'actif pris en charge.", "unsupported_asset": "Nous ne prenons pas en charge cette action pour cet élément. Veuillez créer ou passer à un portefeuille d'un type d'actif pris en charge.",
"uptime": "Durée de la baisse",
"upto": "jusqu'à ${value}", "upto": "jusqu'à ${value}",
"use": "Changer vers code PIN à ", "use": "Changer vers code PIN à ",
"use_card_info_three": "Utilisez la carte numérique en ligne ou avec des méthodes de paiement sans contact.", "use_card_info_three": "Utilisez la carte numérique en ligne ou avec des méthodes de paiement sans contact.",
@ -757,6 +772,7 @@
"view_key_private": "Clef d'audit (view key) (privée)", "view_key_private": "Clef d'audit (view key) (privée)",
"view_key_public": "Clef d'audit (view key) (publique)", "view_key_public": "Clef d'audit (view key) (publique)",
"view_transaction_on": "Voir la Transaction sur ", "view_transaction_on": "Voir la Transaction sur ",
"voting_weight": "Poids de vote",
"waitFewSecondForTxUpdate": "Veuillez attendre quelques secondes pour que la transaction soit reflétée dans l'historique des transactions.", "waitFewSecondForTxUpdate": "Veuillez attendre quelques secondes pour que la transaction soit reflétée dans l'historique des transactions.",
"wallet_keys": "Phrase secrète (seed)/Clefs du portefeuille (wallet)", "wallet_keys": "Phrase secrète (seed)/Clefs du portefeuille (wallet)",
"wallet_list_create_new_wallet": "Créer un Nouveau Portefeuille (Wallet)", "wallet_list_create_new_wallet": "Créer un Nouveau Portefeuille (Wallet)",

View file

@ -59,6 +59,7 @@
"auth_store_incorrect_password": "PIN na gaskiya", "auth_store_incorrect_password": "PIN na gaskiya",
"authenticated": "Ingantacce", "authenticated": "Ingantacce",
"authentication": "Tabbatarwa", "authentication": "Tabbatarwa",
"auto_generate_addresses": "Adireshin Auto",
"auto_generate_subaddresses": "Saɓaƙa subaddresses ta kai tsaye", "auto_generate_subaddresses": "Saɓaƙa subaddresses ta kai tsaye",
"automatic": "Na atomatik", "automatic": "Na atomatik",
"available_balance": "KUDI", "available_balance": "KUDI",
@ -81,6 +82,7 @@
"breez_warning_disruption": "A halin yanzu sabis na Breez yana fuskantar al'amura. Da fatan za a sake gwadawa nan gaba.", "breez_warning_disruption": "A halin yanzu sabis na Breez yana fuskantar al'amura. Da fatan za a sake gwadawa nan gaba.",
"breez_warning_maintenance": "A halin yanzu ana samun sabis na BREEZ a halin yanzu. Da fatan za a sake gwadawa nan gaba.", "breez_warning_maintenance": "A halin yanzu ana samun sabis na BREEZ a halin yanzu. Da fatan za a sake gwadawa nan gaba.",
"bright_theme": "Mai haske", "bright_theme": "Mai haske",
"bump_fee": "Buin",
"buy": "Sayi", "buy": "Sayi",
"buy_alert_content": "A halin yanzu muna tallafawa kawai siyan Bitcoin, Ethereum, Litecoin, da Monero. Da fatan za a ƙirƙiri ko canza zuwa Bitcoin, Ethereum, Litecoin, ko Monero walat.", "buy_alert_content": "A halin yanzu muna tallafawa kawai siyan Bitcoin, Ethereum, Litecoin, da Monero. Da fatan za a ƙirƙiri ko canza zuwa Bitcoin, Ethereum, Litecoin, ko Monero walat.",
"buy_bitcoin": "Sayi Bitcoin", "buy_bitcoin": "Sayi Bitcoin",
@ -135,6 +137,8 @@
"confirm": "Tabbatar", "confirm": "Tabbatar",
"confirm_delete_template": "Wannan aikin zai share wannan samfuri. Kuna so ku ci gaba?", "confirm_delete_template": "Wannan aikin zai share wannan samfuri. Kuna so ku ci gaba?",
"confirm_delete_wallet": "Wannan aikin zai share wannan walat. Kuna so ku ci gaba?", "confirm_delete_wallet": "Wannan aikin zai share wannan walat. Kuna so ku ci gaba?",
"confirm_fee_deduction": "Tabbatar da cire kudade",
"confirm_fee_deduction_content": "Shin kun yarda ku cire kuɗin daga fitarwa?",
"confirm_sending": "Tabbatar da aikawa", "confirm_sending": "Tabbatar da aikawa",
"confirmations": "Tabbatar", "confirmations": "Tabbatar",
"confirmed": "An tabbatar", "confirmed": "An tabbatar",
@ -174,6 +178,7 @@
"debit_card": "Katin Zare kudi", "debit_card": "Katin Zare kudi",
"debit_card_terms": "Adana da amfani da lambar katin kuɗin ku (da takaddun shaida masu dacewa da lambar katin kuɗin ku) a cikin wannan walat ɗin dijital suna ƙarƙashin Sharuɗɗa da Sharuɗɗa na yarjejeniya mai amfani da katin tare da mai fitar da katin biyan kuɗi, kamar yadda yake aiki daga lokaci zuwa lokaci.", "debit_card_terms": "Adana da amfani da lambar katin kuɗin ku (da takaddun shaida masu dacewa da lambar katin kuɗin ku) a cikin wannan walat ɗin dijital suna ƙarƙashin Sharuɗɗa da Sharuɗɗa na yarjejeniya mai amfani da katin tare da mai fitar da katin biyan kuɗi, kamar yadda yake aiki daga lokaci zuwa lokaci.",
"decimal_places_error": "Wadannan suna da tsawon harsuna", "decimal_places_error": "Wadannan suna da tsawon harsuna",
"decimals_cannot_be_zero": "Alamar alama ba zata iya zama sifili ba.",
"default_buy_provider": "Tsohuwar Siyarwa", "default_buy_provider": "Tsohuwar Siyarwa",
"default_sell_provider": "Tsohuwar Mai Bayar Siyarwa", "default_sell_provider": "Tsohuwar Mai Bayar Siyarwa",
"delete": "Share", "delete": "Share",
@ -214,6 +219,7 @@
"edit_token": "Gyara alamar", "edit_token": "Gyara alamar",
"electrum_address_disclaimer": "Muna samar da sababbin adireshi duk lokacin da kuka yi amfani da ɗaya, amma adiresoshin da suka gabata suna ci gaba da aiki", "electrum_address_disclaimer": "Muna samar da sababbin adireshi duk lokacin da kuka yi amfani da ɗaya, amma adiresoshin da suka gabata suna ci gaba da aiki",
"email_address": "Adireshin i-mel", "email_address": "Adireshin i-mel",
"enable_replace_by_fee": "Ba da damar maye gurbin-by-kudin",
"enabled": "An kunna", "enabled": "An kunna",
"enter_amount": "Shigar da Adadi", "enter_amount": "Shigar da Adadi",
"enter_backup_password": "Shigar da kalmar wucewa ta madadin nan", "enter_backup_password": "Shigar da kalmar wucewa ta madadin nan",
@ -250,6 +256,7 @@
"errorGettingCredentials": "Ba a yi nasara ba: Kuskure yayin samun takaddun shaida", "errorGettingCredentials": "Ba a yi nasara ba: Kuskure yayin samun takaddun shaida",
"errorSigningTransaction": "An sami kuskure yayin sanya hannu kan ciniki", "errorSigningTransaction": "An sami kuskure yayin sanya hannu kan ciniki",
"estimated": "Kiyasta", "estimated": "Kiyasta",
"estimated_new_fee": "An kiyasta sabon kudin",
"etherscan_history": "Etherscan tarihin kowane zamani", "etherscan_history": "Etherscan tarihin kowane zamani",
"event": "Lamarin", "event": "Lamarin",
"events": "Abubuwan da suka faru", "events": "Abubuwan da suka faru",
@ -316,6 +323,7 @@
"in_store": "A cikin Store", "in_store": "A cikin Store",
"incoming": "Mai shigowa", "incoming": "Mai shigowa",
"incorrect_seed": "rubutun da aka shigar ba shi da inganci.", "incorrect_seed": "rubutun da aka shigar ba shi da inganci.",
"inputs": "Abubuwan da ke ciki",
"introducing_cake_pay": "Gabatar da Cake Pay!", "introducing_cake_pay": "Gabatar da Cake Pay!",
"invalid_input": "Shigar da ba daidai ba", "invalid_input": "Shigar da ba daidai ba",
"invoice": "Daftari", "invoice": "Daftari",
@ -358,6 +366,8 @@
"moonpay_alert_text": "Darajar adadin dole ne ya zama fiye ko daidai da ${minAmount} ${fiatCurrency}", "moonpay_alert_text": "Darajar adadin dole ne ya zama fiye ko daidai da ${minAmount} ${fiatCurrency}",
"more_options": "Ƙarin Zaɓuɓɓuka", "more_options": "Ƙarin Zaɓuɓɓuka",
"name": "Suna", "name": "Suna",
"nano_current_rep": "Wakilin Yanzu",
"nano_pick_new_rep": "Dauki sabon wakili",
"narrow": "kunkuntar", "narrow": "kunkuntar",
"new_first_wallet_text": "A sauƙaƙe kiyaye kuzarin ku", "new_first_wallet_text": "A sauƙaƙe kiyaye kuzarin ku",
"new_node_testing": "Sabbin gwajin kumburi", "new_node_testing": "Sabbin gwajin kumburi",
@ -390,6 +400,7 @@
"offer_expires_in": "tayin zai ƙare a:", "offer_expires_in": "tayin zai ƙare a:",
"offline": "Offline", "offline": "Offline",
"ok": "OK", "ok": "OK",
"old_fee": "Tsohon kudin",
"onion_link": "Lambar onion", "onion_link": "Lambar onion",
"online": "Kan layi", "online": "Kan layi",
"onramper_option_description": "Da sauri sayi Crypto tare da hanyoyin biyan kuɗi da yawa. Akwai a yawancin ƙasashe. Yaduwa da kudade sun bambanta.", "onramper_option_description": "Da sauri sayi Crypto tare da hanyoyin biyan kuɗi da yawa. Akwai a yawancin ƙasashe. Yaduwa da kudade sun bambanta.",
@ -408,6 +419,7 @@
"outdated_electrum_wallet_description": "Sabbin walat ɗin Bitcoin da aka kirkira a cikin Cake yanzu suna da nau'in kalma 24. Ya zama dole ka ƙirƙiri sabon walat ɗin Bitcoin kuma canza duk kuɗin ku zuwa sabon walat ɗin kalmomi 24, kuma ku daina amfani da walat tare da iri mai kalma 12. Da fatan za a yi haka nan take don samun kuɗin ku.", "outdated_electrum_wallet_description": "Sabbin walat ɗin Bitcoin da aka kirkira a cikin Cake yanzu suna da nau'in kalma 24. Ya zama dole ka ƙirƙiri sabon walat ɗin Bitcoin kuma canza duk kuɗin ku zuwa sabon walat ɗin kalmomi 24, kuma ku daina amfani da walat tare da iri mai kalma 12. Da fatan za a yi haka nan take don samun kuɗin ku.",
"outdated_electrum_wallet_receive_warning": "Idan wannan walat ɗin yana da nau'in kalma 12 kuma an ƙirƙira shi a cikin Cake, KAR KA saka Bitcoin cikin wannan jakar. Duk wani BTC da aka canjawa wuri zuwa wannan walat na iya ɓacewa. Ƙirƙiri sabon walat mai kalmomi 24 (matsa menu a saman dama, zaɓi Wallets, zaɓi Ƙirƙiri Sabon Wallet, sannan zaɓi Bitcoin) kuma NAN nan take matsar da BTC ɗin ku a can. Sabbin (kalmomi 24) BTC wallets daga Cake suna da tsaro", "outdated_electrum_wallet_receive_warning": "Idan wannan walat ɗin yana da nau'in kalma 12 kuma an ƙirƙira shi a cikin Cake, KAR KA saka Bitcoin cikin wannan jakar. Duk wani BTC da aka canjawa wuri zuwa wannan walat na iya ɓacewa. Ƙirƙiri sabon walat mai kalmomi 24 (matsa menu a saman dama, zaɓi Wallets, zaɓi Ƙirƙiri Sabon Wallet, sannan zaɓi Bitcoin) kuma NAN nan take matsar da BTC ɗin ku a can. Sabbin (kalmomi 24) BTC wallets daga Cake suna da tsaro",
"outgoing": "Mai fita", "outgoing": "Mai fita",
"outputs": "Abubuwan fashewa",
"overwrite_amount": "Rubuta adadin", "overwrite_amount": "Rubuta adadin",
"pairingInvalidEvent": "Haɗa Lamarin mara inganci", "pairingInvalidEvent": "Haɗa Lamarin mara inganci",
"password": "Kalmar wucewa", "password": "Kalmar wucewa",
@ -466,6 +478,8 @@
"remove_node": "Cire node", "remove_node": "Cire node",
"remove_node_message": "Kuna tabbatar kuna so ku cire wannan node?", "remove_node_message": "Kuna tabbatar kuna so ku cire wannan node?",
"rename": "Sake suna", "rename": "Sake suna",
"rep_warning": "Gargadi Wakilin",
"rep_warning_sub": "Wakilinku bai bayyana ya kasance cikin kyakkyawan yanayi ba. Matsa nan don zaɓar sabon",
"require_for_adding_contacts": "Bukatar ƙara lambobin sadarwa", "require_for_adding_contacts": "Bukatar ƙara lambobin sadarwa",
"require_for_all_security_and_backup_settings": "Bukatar duk tsaro da saitunan wariyar ajiya", "require_for_all_security_and_backup_settings": "Bukatar duk tsaro da saitunan wariyar ajiya",
"require_for_assessing_wallet": "Bukatar samun damar walat", "require_for_assessing_wallet": "Bukatar samun damar walat",
@ -743,6 +757,7 @@
"unspent_coins_details_title": "Bayanan tsabar kudi da ba a kashe ba", "unspent_coins_details_title": "Bayanan tsabar kudi da ba a kashe ba",
"unspent_coins_title": "Tsabar da ba a kashe ba", "unspent_coins_title": "Tsabar da ba a kashe ba",
"unsupported_asset": "Ba mu goyi bayan wannan aikin don wannan kadara. Da fatan za a ƙirƙira ko canza zuwa walat na nau'in kadara mai tallafi.", "unsupported_asset": "Ba mu goyi bayan wannan aikin don wannan kadara. Da fatan za a ƙirƙira ko canza zuwa walat na nau'in kadara mai tallafi.",
"uptime": "Sama",
"upto": "har zuwa ${value}", "upto": "har zuwa ${value}",
"use": "Canja zuwa", "use": "Canja zuwa",
"use_card_info_three": "Yi amfani da katin dijital akan layi ko tare da hanyoyin biyan kuɗi mara lamba.", "use_card_info_three": "Yi amfani da katin dijital akan layi ko tare da hanyoyin biyan kuɗi mara lamba.",
@ -759,6 +774,7 @@
"view_key_private": "Duba maɓallin (maɓallin kalmar sirri)", "view_key_private": "Duba maɓallin (maɓallin kalmar sirri)",
"view_key_public": "Maɓallin Duba (maɓallin jama'a)", "view_key_public": "Maɓallin Duba (maɓallin jama'a)",
"view_transaction_on": "Dubo aikace-aikacen akan", "view_transaction_on": "Dubo aikace-aikacen akan",
"voting_weight": "Nauyi mai nauyi",
"waitFewSecondForTxUpdate": "Da fatan za a jira ƴan daƙiƙa don ciniki don yin tunani a tarihin ma'amala", "waitFewSecondForTxUpdate": "Da fatan za a jira ƴan daƙiƙa don ciniki don yin tunani a tarihin ma'amala",
"wallet_keys": "Iri/maɓalli na walat", "wallet_keys": "Iri/maɓalli na walat",
"wallet_list_create_new_wallet": "Ƙirƙiri Sabon Wallet", "wallet_list_create_new_wallet": "Ƙirƙiri Sabon Wallet",

View file

@ -59,6 +59,7 @@
"auth_store_incorrect_password": "गलत पिन", "auth_store_incorrect_password": "गलत पिन",
"authenticated": "प्रमाणीकृत", "authenticated": "प्रमाणीकृत",
"authentication": "प्रमाणीकरण", "authentication": "प्रमाणीकरण",
"auto_generate_addresses": "ऑटो उत्पन्न पते",
"auto_generate_subaddresses": "स्वचालित रूप से उप-पते उत्पन्न करें", "auto_generate_subaddresses": "स्वचालित रूप से उप-पते उत्पन्न करें",
"automatic": "स्वचालित", "automatic": "स्वचालित",
"available_balance": "उपलब्ध शेष राशि", "available_balance": "उपलब्ध शेष राशि",
@ -81,6 +82,7 @@
"breez_warning_disruption": "ब्रीज़ सेवा वर्तमान में मुद्दों का अनुभव कर रही है। कृपया बाद में पुन: प्रयास करें।", "breez_warning_disruption": "ब्रीज़ सेवा वर्तमान में मुद्दों का अनुभव कर रही है। कृपया बाद में पुन: प्रयास करें।",
"breez_warning_maintenance": "ब्रीज़ सेवा वर्तमान में रखरखाव से गुजर रही है। कृपया बाद में पुन: प्रयास करें।", "breez_warning_maintenance": "ब्रीज़ सेवा वर्तमान में रखरखाव से गुजर रही है। कृपया बाद में पुन: प्रयास करें।",
"bright_theme": "उज्ज्वल", "bright_theme": "उज्ज्वल",
"bump_fee": "बम्प फीस",
"buy": "खरीदें", "buy": "खरीदें",
"buy_alert_content": "वर्तमान में हम केवल बिटकॉइन, एथेरियम, लाइटकॉइन और मोनेरो की खरीद का समर्थन करते हैं। कृपया अपना बिटकॉइन, एथेरियम, लाइटकॉइन, या मोनेरो वॉलेट बनाएं या उस पर स्विच करें।", "buy_alert_content": "वर्तमान में हम केवल बिटकॉइन, एथेरियम, लाइटकॉइन और मोनेरो की खरीद का समर्थन करते हैं। कृपया अपना बिटकॉइन, एथेरियम, लाइटकॉइन, या मोनेरो वॉलेट बनाएं या उस पर स्विच करें।",
"buy_bitcoin": "बिटकॉइन खरीदें", "buy_bitcoin": "बिटकॉइन खरीदें",
@ -135,6 +137,8 @@
"confirm": "की पुष्टि करें", "confirm": "की पुष्टि करें",
"confirm_delete_template": "यह क्रिया इस टेम्पलेट को हटा देगी। क्या आप जारी रखना चाहते हैं?", "confirm_delete_template": "यह क्रिया इस टेम्पलेट को हटा देगी। क्या आप जारी रखना चाहते हैं?",
"confirm_delete_wallet": "यह क्रिया इस वॉलेट को हटा देगी। क्या आप जारी रखना चाहते हैं?", "confirm_delete_wallet": "यह क्रिया इस वॉलेट को हटा देगी। क्या आप जारी रखना चाहते हैं?",
"confirm_fee_deduction": "शुल्क कटौती की पुष्टि करें",
"confirm_fee_deduction_content": "क्या आप आउटपुट से शुल्क में कटौती करने के लिए सहमत हैं?",
"confirm_sending": "भेजने की पुष्टि करें", "confirm_sending": "भेजने की पुष्टि करें",
"confirmations": "पुष्टिकरण", "confirmations": "पुष्टिकरण",
"confirmed": "पुष्टि की गई शेष राशिी", "confirmed": "पुष्टि की गई शेष राशिी",
@ -174,6 +178,7 @@
"debit_card": "डेबिट कार्ड", "debit_card": "डेबिट कार्ड",
"debit_card_terms": "इस डिजिटल वॉलेट में आपके भुगतान कार्ड नंबर (और आपके भुगतान कार्ड नंबर से संबंधित क्रेडेंशियल) का भंडारण और उपयोग भुगतान कार्ड जारीकर्ता के साथ लागू कार्डधारक समझौते के नियमों और शर्तों के अधीन है, जैसा कि प्रभावी है समय - समय पर।", "debit_card_terms": "इस डिजिटल वॉलेट में आपके भुगतान कार्ड नंबर (और आपके भुगतान कार्ड नंबर से संबंधित क्रेडेंशियल) का भंडारण और उपयोग भुगतान कार्ड जारीकर्ता के साथ लागू कार्डधारक समझौते के नियमों और शर्तों के अधीन है, जैसा कि प्रभावी है समय - समय पर।",
"decimal_places_error": "बहुत अधिक दशमलव स्थान", "decimal_places_error": "बहुत अधिक दशमलव स्थान",
"decimals_cannot_be_zero": "टोकन दशमलव शून्य नहीं हो सकता।",
"default_buy_provider": "डिफ़ॉल्ट खरीद प्रदाता", "default_buy_provider": "डिफ़ॉल्ट खरीद प्रदाता",
"default_sell_provider": "डिफ़ॉल्ट विक्रय प्रदाता", "default_sell_provider": "डिफ़ॉल्ट विक्रय प्रदाता",
"delete": "हटाएं", "delete": "हटाएं",
@ -214,6 +219,7 @@
"edit_token": "टोकन संपादित करें", "edit_token": "टोकन संपादित करें",
"electrum_address_disclaimer": "हर बार जब आप एक का उपयोग करते हैं तो हम नए पते उत्पन्न करते हैं, लेकिन पिछले पते काम करना जारी रखते हैं", "electrum_address_disclaimer": "हर बार जब आप एक का उपयोग करते हैं तो हम नए पते उत्पन्न करते हैं, लेकिन पिछले पते काम करना जारी रखते हैं",
"email_address": "ईमेल पता", "email_address": "ईमेल पता",
"enable_replace_by_fee": "प्रतिस्थापित-दर-शुल्क सक्षम करें",
"enabled": "सक्रिय", "enabled": "सक्रिय",
"enter_amount": "राशि दर्ज करें", "enter_amount": "राशि दर्ज करें",
"enter_backup_password": "यहां बैकअप पासवर्ड डालें", "enter_backup_password": "यहां बैकअप पासवर्ड डालें",
@ -250,6 +256,7 @@
"errorGettingCredentials": "विफल: क्रेडेंशियल प्राप्त करते समय त्रुटि", "errorGettingCredentials": "विफल: क्रेडेंशियल प्राप्त करते समय त्रुटि",
"errorSigningTransaction": "लेन-देन पर हस्ताक्षर करते समय एक त्रुटि उत्पन्न हुई है", "errorSigningTransaction": "लेन-देन पर हस्ताक्षर करते समय एक त्रुटि उत्पन्न हुई है",
"estimated": "अनुमानित", "estimated": "अनुमानित",
"estimated_new_fee": "अनुमानित नया शुल्क",
"etherscan_history": "इथरस्कैन इतिहास", "etherscan_history": "इथरस्कैन इतिहास",
"event": "आयोजन", "event": "आयोजन",
"events": "आयोजन", "events": "आयोजन",
@ -316,6 +323,7 @@
"in_store": "स्टोर में", "in_store": "स्टोर में",
"incoming": "आने वाली", "incoming": "आने वाली",
"incorrect_seed": "दर्ज किया गया पाठ मान्य नहीं है।", "incorrect_seed": "दर्ज किया गया पाठ मान्य नहीं है।",
"inputs": "इनपुट",
"introducing_cake_pay": "परिचय Cake Pay!", "introducing_cake_pay": "परिचय Cake Pay!",
"invalid_input": "अमान्य निवेश", "invalid_input": "अमान्य निवेश",
"invoice": "चालान", "invoice": "चालान",
@ -358,6 +366,8 @@
"moonpay_alert_text": "राशि का मूल्य अधिक है या करने के लिए बराबर होना चाहिए ${minAmount} ${fiatCurrency}", "moonpay_alert_text": "राशि का मूल्य अधिक है या करने के लिए बराबर होना चाहिए ${minAmount} ${fiatCurrency}",
"more_options": "और विकल्प", "more_options": "और विकल्प",
"name": "नाम", "name": "नाम",
"nano_current_rep": "वर्तमान प्रतिनिधि",
"nano_pick_new_rep": "एक नया प्रतिनिधि चुनें",
"narrow": "सँकरा", "narrow": "सँकरा",
"new_first_wallet_text": "आसानी से अपनी क्रिप्टोक्यूरेंसी को सुरक्षित रखें", "new_first_wallet_text": "आसानी से अपनी क्रिप्टोक्यूरेंसी को सुरक्षित रखें",
"new_node_testing": "नई नोड परीक्षण", "new_node_testing": "नई नोड परीक्षण",
@ -390,6 +400,7 @@
"offer_expires_in": "में ऑफर समाप्त हो रहा है: ", "offer_expires_in": "में ऑफर समाप्त हो रहा है: ",
"offline": "ऑफ़लाइन", "offline": "ऑफ़लाइन",
"ok": "ठीक है", "ok": "ठीक है",
"old_fee": "पुराना फीस",
"onion_link": "प्याज का लिंक", "onion_link": "प्याज का लिंक",
"online": "ऑनलाइन", "online": "ऑनलाइन",
"onramper_option_description": "जल्दी से कई भुगतान विधियों के साथ क्रिप्टो खरीदें। अधिकांश देशों में उपलब्ध है। फैलता है और फीस अलग -अलग होती है।", "onramper_option_description": "जल्दी से कई भुगतान विधियों के साथ क्रिप्टो खरीदें। अधिकांश देशों में उपलब्ध है। फैलता है और फीस अलग -अलग होती है।",
@ -406,6 +417,7 @@
"outdated_electrum_wallet_description": "केक में बनाए गए नए बिटकॉइन वॉलेट में अब 24-शब्द का बीज है। यह अनिवार्य है कि आप एक नया बिटकॉइन वॉलेट बनाएं और अपने सभी फंड को नए 24-शब्द वाले वॉलेट में स्थानांतरित करें, और 12-शब्द बीज वाले वॉलेट का उपयोग करना बंद करें। कृपया अपने धन को सुरक्षित करने के लिए इसे तुरंत करें।", "outdated_electrum_wallet_description": "केक में बनाए गए नए बिटकॉइन वॉलेट में अब 24-शब्द का बीज है। यह अनिवार्य है कि आप एक नया बिटकॉइन वॉलेट बनाएं और अपने सभी फंड को नए 24-शब्द वाले वॉलेट में स्थानांतरित करें, और 12-शब्द बीज वाले वॉलेट का उपयोग करना बंद करें। कृपया अपने धन को सुरक्षित करने के लिए इसे तुरंत करें।",
"outdated_electrum_wallet_receive_warning": "अगर इस वॉलेट में 12 शब्दों का बीज है और इसे केक में बनाया गया है, तो इस वॉलेट में बिटकॉइन जमा न करें। इस वॉलेट में स्थानांतरित किया गया कोई भी बीटीसी खो सकता है। एक नया 24-शब्द वॉलेट बनाएं (ऊपर दाईं ओर स्थित मेनू पर टैप करें, वॉलेट चुनें, नया वॉलेट बनाएं चुनें, फिर बिटकॉइन चुनें) और तुरंत अपना बीटीसी वहां ले जाएं। केक से नए (24-शब्द) बीटीसी वॉलेट सुरक्षित हैं", "outdated_electrum_wallet_receive_warning": "अगर इस वॉलेट में 12 शब्दों का बीज है और इसे केक में बनाया गया है, तो इस वॉलेट में बिटकॉइन जमा न करें। इस वॉलेट में स्थानांतरित किया गया कोई भी बीटीसी खो सकता है। एक नया 24-शब्द वॉलेट बनाएं (ऊपर दाईं ओर स्थित मेनू पर टैप करें, वॉलेट चुनें, नया वॉलेट बनाएं चुनें, फिर बिटकॉइन चुनें) और तुरंत अपना बीटीसी वहां ले जाएं। केक से नए (24-शब्द) बीटीसी वॉलेट सुरक्षित हैं",
"outgoing": "निवर्तमान", "outgoing": "निवर्तमान",
"outputs": "आउटपुट",
"overwrite_amount": "Overwrite amount", "overwrite_amount": "Overwrite amount",
"pairingInvalidEvent": "अमान्य ईवेंट युग्मित करना", "pairingInvalidEvent": "अमान्य ईवेंट युग्मित करना",
"password": "पारण शब्द", "password": "पारण शब्द",
@ -466,6 +478,8 @@
"remove_node": "नोड निकालें", "remove_node": "नोड निकालें",
"remove_node_message": "क्या आप वाकई चयनित नोड को निकालना चाहते हैं?", "remove_node_message": "क्या आप वाकई चयनित नोड को निकालना चाहते हैं?",
"rename": "नाम बदलें", "rename": "नाम बदलें",
"rep_warning": "प्रतिनिधि चेतावनी",
"rep_warning_sub": "आपका प्रतिनिधि अच्छी स्थिति में नहीं दिखाई देता है। एक नया चयन करने के लिए यहां टैप करें",
"require_for_adding_contacts": "संपर्क जोड़ने के लिए आवश्यकता है", "require_for_adding_contacts": "संपर्क जोड़ने के लिए आवश्यकता है",
"require_for_all_security_and_backup_settings": "सभी सुरक्षा और बैकअप सेटिंग्स की आवश्यकता है", "require_for_all_security_and_backup_settings": "सभी सुरक्षा और बैकअप सेटिंग्स की आवश्यकता है",
"require_for_assessing_wallet": "वॉलेट तक पहुँचने के लिए आवश्यकता है", "require_for_assessing_wallet": "वॉलेट तक पहुँचने के लिए आवश्यकता है",
@ -743,6 +757,7 @@
"unspent_coins_details_title": "अव्ययित सिक्कों का विवरण", "unspent_coins_details_title": "अव्ययित सिक्कों का विवरण",
"unspent_coins_title": "खर्च न किए गए सिक्के", "unspent_coins_title": "खर्च न किए गए सिक्के",
"unsupported_asset": "हम इस संपत्ति के लिए इस कार्रवाई का समर्थन नहीं करते हैं. कृपया समर्थित परिसंपत्ति प्रकार का वॉलेट बनाएं या उस पर स्विच करें।", "unsupported_asset": "हम इस संपत्ति के लिए इस कार्रवाई का समर्थन नहीं करते हैं. कृपया समर्थित परिसंपत्ति प्रकार का वॉलेट बनाएं या उस पर स्विच करें।",
"uptime": "अपटाइम",
"upto": "${value} तक", "upto": "${value} तक",
"use": "उपयोग ", "use": "उपयोग ",
"use_card_info_three": "डिजिटल कार्ड का ऑनलाइन या संपर्क रहित भुगतान विधियों के साथ उपयोग करें।", "use_card_info_three": "डिजिटल कार्ड का ऑनलाइन या संपर्क रहित भुगतान विधियों के साथ उपयोग करें।",
@ -759,6 +774,7 @@
"view_key_private": "कुंजी देखें(निजी)", "view_key_private": "कुंजी देखें(निजी)",
"view_key_public": "कुंजी देखें (जनता)", "view_key_public": "कुंजी देखें (जनता)",
"view_transaction_on": "View Transaction on ", "view_transaction_on": "View Transaction on ",
"voting_weight": "वोटिंग वेट",
"waitFewSecondForTxUpdate": "लेन-देन इतिहास में लेन-देन प्रतिबिंबित होने के लिए कृपया कुछ सेकंड प्रतीक्षा करें", "waitFewSecondForTxUpdate": "लेन-देन इतिहास में लेन-देन प्रतिबिंबित होने के लिए कृपया कुछ सेकंड प्रतीक्षा करें",
"wallet_keys": "बटुआ बीज / चाबियाँ", "wallet_keys": "बटुआ बीज / चाबियाँ",
"wallet_list_create_new_wallet": "नया बटुआ बनाएँ", "wallet_list_create_new_wallet": "नया बटुआ बनाएँ",

View file

@ -59,6 +59,7 @@
"auth_store_incorrect_password": "Pogrešan PIN", "auth_store_incorrect_password": "Pogrešan PIN",
"authenticated": "Autentificiran", "authenticated": "Autentificiran",
"authentication": "Autentifikacija", "authentication": "Autentifikacija",
"auto_generate_addresses": "Automatsko generiranje adresa",
"auto_generate_subaddresses": "Automatski generirajte podadrese", "auto_generate_subaddresses": "Automatski generirajte podadrese",
"automatic": "Automatski", "automatic": "Automatski",
"available_balance": "Raspoloživ iznos", "available_balance": "Raspoloživ iznos",
@ -81,6 +82,7 @@
"breez_warning_disruption": "Breez usluga trenutno ima problema. Molimo pokušajte ponovo kasnije.", "breez_warning_disruption": "Breez usluga trenutno ima problema. Molimo pokušajte ponovo kasnije.",
"breez_warning_maintenance": "Breez usluga trenutno je u održavanju. Molimo pokušajte ponovo kasnije.", "breez_warning_maintenance": "Breez usluga trenutno je u održavanju. Molimo pokušajte ponovo kasnije.",
"bright_theme": "Jarka", "bright_theme": "Jarka",
"bump_fee": "Naplata",
"buy": "Kupi", "buy": "Kupi",
"buy_alert_content": "Trenutno podržavamo samo kupnju Bitcoina, Ethereuma, Litecoina i Monera. Izradite ili prijeđite na svoj Bitcoin, Ethereum, Litecoin ili Monero novčanik.", "buy_alert_content": "Trenutno podržavamo samo kupnju Bitcoina, Ethereuma, Litecoina i Monera. Izradite ili prijeđite na svoj Bitcoin, Ethereum, Litecoin ili Monero novčanik.",
"buy_bitcoin": "Kupite Bitcoin", "buy_bitcoin": "Kupite Bitcoin",
@ -135,6 +137,8 @@
"confirm": "Potvrdi", "confirm": "Potvrdi",
"confirm_delete_template": "Ovom ćete radnjom izbrisati ovaj predložak. Želite li nastaviti?", "confirm_delete_template": "Ovom ćete radnjom izbrisati ovaj predložak. Želite li nastaviti?",
"confirm_delete_wallet": "Ovom ćete radnjom izbrisati ovaj novčanik. Želite li nastaviti?", "confirm_delete_wallet": "Ovom ćete radnjom izbrisati ovaj novčanik. Želite li nastaviti?",
"confirm_fee_deduction": "Potvrdite odbitak naknade",
"confirm_fee_deduction_content": "Slažete li se da ćete odbiti naknadu od izlaza?",
"confirm_sending": "Potvrdi slanje", "confirm_sending": "Potvrdi slanje",
"confirmations": "Potvrde", "confirmations": "Potvrde",
"confirmed": "Potvrđeno stanje", "confirmed": "Potvrđeno stanje",
@ -174,6 +178,7 @@
"debit_card": "Debitna kartica", "debit_card": "Debitna kartica",
"debit_card_terms": "Pohranjivanje i korištenje broja vaše platne kartice (i vjerodajnica koje odgovaraju broju vaše platne kartice) u ovom digitalnom novčaniku podliježu Uvjetima i odredbama važećeg ugovora vlasnika kartice s izdavateljem platne kartice, koji su na snazi od S vremena na vrijeme.", "debit_card_terms": "Pohranjivanje i korištenje broja vaše platne kartice (i vjerodajnica koje odgovaraju broju vaše platne kartice) u ovom digitalnom novčaniku podliježu Uvjetima i odredbama važećeg ugovora vlasnika kartice s izdavateljem platne kartice, koji su na snazi od S vremena na vrijeme.",
"decimal_places_error": "Previše decimalnih mjesta", "decimal_places_error": "Previše decimalnih mjesta",
"decimals_cannot_be_zero": "Token Decimal ne može biti nula.",
"default_buy_provider": "Zadani davatelj kupnje", "default_buy_provider": "Zadani davatelj kupnje",
"default_sell_provider": "Zadani dobavljač prodaje", "default_sell_provider": "Zadani dobavljač prodaje",
"delete": "Izbriši", "delete": "Izbriši",
@ -214,6 +219,7 @@
"edit_token": "Uredi token", "edit_token": "Uredi token",
"electrum_address_disclaimer": "Minden egyes alkalommal új címeket generálunk, de a korábbi címek továbbra is működnek", "electrum_address_disclaimer": "Minden egyes alkalommal új címeket generálunk, de a korábbi címek továbbra is működnek",
"email_address": "Adresa e-pošte", "email_address": "Adresa e-pošte",
"enable_replace_by_fee": "Omogući zamjenu",
"enabled": "Omogućeno", "enabled": "Omogućeno",
"enter_amount": "Unesite iznos", "enter_amount": "Unesite iznos",
"enter_backup_password": "Unesite svoju lozinku za sigurnosnu kopiju ovdje", "enter_backup_password": "Unesite svoju lozinku za sigurnosnu kopiju ovdje",
@ -250,6 +256,7 @@
"errorGettingCredentials": "Neuspješno: Pogreška prilikom dobivanja vjerodajnica", "errorGettingCredentials": "Neuspješno: Pogreška prilikom dobivanja vjerodajnica",
"errorSigningTransaction": "Došlo je do pogreške prilikom potpisivanja transakcije", "errorSigningTransaction": "Došlo je do pogreške prilikom potpisivanja transakcije",
"estimated": "procijenjen", "estimated": "procijenjen",
"estimated_new_fee": "Procijenjena nova naknada",
"etherscan_history": "Etherscan povijest", "etherscan_history": "Etherscan povijest",
"event": "Događaj", "event": "Događaj",
"events": "Događaji", "events": "Događaji",
@ -316,6 +323,7 @@
"in_store": "U trgovini", "in_store": "U trgovini",
"incoming": "Dolazno", "incoming": "Dolazno",
"incorrect_seed": "Uneseni tekst nije valjan.", "incorrect_seed": "Uneseni tekst nije valjan.",
"inputs": "Unosi",
"introducing_cake_pay": "Predstavljamo Cake Pay!", "introducing_cake_pay": "Predstavljamo Cake Pay!",
"invalid_input": "Pogrešan unos", "invalid_input": "Pogrešan unos",
"invoice": "Dostavnica", "invoice": "Dostavnica",
@ -358,6 +366,8 @@
"moonpay_alert_text": "Vrijednost iznosa mora biti veća ili jednaka ${minAmount} ${fiatCurrency}", "moonpay_alert_text": "Vrijednost iznosa mora biti veća ili jednaka ${minAmount} ${fiatCurrency}",
"more_options": "Više opcija", "more_options": "Više opcija",
"name": "Ime", "name": "Ime",
"nano_current_rep": "Trenutni predstavnik",
"nano_pick_new_rep": "Odaberite novog predstavnika",
"narrow": "Usko", "narrow": "Usko",
"new_first_wallet_text": "Jednostavno čuvajte svoju kripto valutu", "new_first_wallet_text": "Jednostavno čuvajte svoju kripto valutu",
"new_node_testing": "Provjera novog nodea", "new_node_testing": "Provjera novog nodea",
@ -390,6 +400,7 @@
"offer_expires_in": "Ponuda istječe za: ", "offer_expires_in": "Ponuda istječe za: ",
"offline": "izvan mreže", "offline": "izvan mreže",
"ok": "OK", "ok": "OK",
"old_fee": "Stara naknada",
"onion_link": "Poveznica luka", "onion_link": "Poveznica luka",
"online": "Na mreži", "online": "Na mreži",
"onramper_option_description": "Brzo kupite kriptovalute s mnogim načinima plaćanja. Dostupno u većini zemalja. Širenja i naknade variraju.", "onramper_option_description": "Brzo kupite kriptovalute s mnogim načinima plaćanja. Dostupno u većini zemalja. Širenja i naknade variraju.",
@ -406,6 +417,7 @@
"outdated_electrum_wallet_description": "Novi Bitcoin novčanici stvoreni u Cakeu sada imaju sjeme od 24 riječi. Obavezno je stvoriti novi Bitcoin novčanik i prenijeti sva svoja sredstva u novi novčanik od 24 riječi te prestati koristiti novčanike s sjemenkom od 12 riječi. Učinite to odmah kako biste osigurali svoja sredstva.", "outdated_electrum_wallet_description": "Novi Bitcoin novčanici stvoreni u Cakeu sada imaju sjeme od 24 riječi. Obavezno je stvoriti novi Bitcoin novčanik i prenijeti sva svoja sredstva u novi novčanik od 24 riječi te prestati koristiti novčanike s sjemenkom od 12 riječi. Učinite to odmah kako biste osigurali svoja sredstva.",
"outdated_electrum_wallet_receive_warning": "Ako ovaj novčanik sadrži sjeme od 12 riječi i stvoren je u Torti, NEMOJTE polagati Bitcoin u ovaj novčanik. Bilo koji BTC prebačen u ovaj novčanik može se izgubiti. Stvorite novi novčanik od 24 riječi (taknite izbornik u gornjem desnom dijelu, odaberite Novčanici, odaberite Stvori novi novčanik, a zatim odaberite Bitcoin) i ODMAH premjestite svoj BTC tamo. Novi BTC novčanici (s 24 riječi) tvrtke Cake sigurni su", "outdated_electrum_wallet_receive_warning": "Ako ovaj novčanik sadrži sjeme od 12 riječi i stvoren je u Torti, NEMOJTE polagati Bitcoin u ovaj novčanik. Bilo koji BTC prebačen u ovaj novčanik može se izgubiti. Stvorite novi novčanik od 24 riječi (taknite izbornik u gornjem desnom dijelu, odaberite Novčanici, odaberite Stvori novi novčanik, a zatim odaberite Bitcoin) i ODMAH premjestite svoj BTC tamo. Novi BTC novčanici (s 24 riječi) tvrtke Cake sigurni su",
"outgoing": "Odlazno", "outgoing": "Odlazno",
"outputs": "Izlazi",
"overwrite_amount": "Overwrite amount", "overwrite_amount": "Overwrite amount",
"pairingInvalidEvent": "Nevažeći događaj uparivanja", "pairingInvalidEvent": "Nevažeći događaj uparivanja",
"password": "Lozinka", "password": "Lozinka",
@ -464,6 +476,8 @@
"remove_node": "Ukloni node", "remove_node": "Ukloni node",
"remove_node_message": "Jeste li sigurni da želite ukloniti odabrani node?", "remove_node_message": "Jeste li sigurni da želite ukloniti odabrani node?",
"rename": "Preimenuj", "rename": "Preimenuj",
"rep_warning": "Reprezentativno upozorenje",
"rep_warning_sub": "Čini se da vaš predstavnik nije u dobrom stanju. Dodirnite ovdje za odabir novog",
"require_for_adding_contacts": "Zahtijeva za dodavanje kontakata", "require_for_adding_contacts": "Zahtijeva za dodavanje kontakata",
"require_for_all_security_and_backup_settings": "Zahtijeva za sve postavke sigurnosti i sigurnosne kopije", "require_for_all_security_and_backup_settings": "Zahtijeva za sve postavke sigurnosti i sigurnosne kopije",
"require_for_assessing_wallet": "Potreban za pristup novčaniku", "require_for_assessing_wallet": "Potreban za pristup novčaniku",
@ -741,6 +755,7 @@
"unspent_coins_details_title": "Nepotrošeni detalji o novčićima", "unspent_coins_details_title": "Nepotrošeni detalji o novčićima",
"unspent_coins_title": "Nepotrošeni novčići", "unspent_coins_title": "Nepotrošeni novčići",
"unsupported_asset": "Ne podržavamo ovu radnju za ovaj materijal. Izradite ili prijeđite na novčanik podržane vrste sredstava.", "unsupported_asset": "Ne podržavamo ovu radnju za ovaj materijal. Izradite ili prijeđite na novčanik podržane vrste sredstava.",
"uptime": "Radno vrijeme",
"upto": "do ${value}", "upto": "do ${value}",
"use": "Prebaci na", "use": "Prebaci na",
"use_card_info_three": "Koristite digitalnu karticu online ili s beskontaktnim metodama plaćanja.", "use_card_info_three": "Koristite digitalnu karticu online ili s beskontaktnim metodama plaćanja.",
@ -757,6 +772,7 @@
"view_key_private": "View key (privatni)", "view_key_private": "View key (privatni)",
"view_key_public": "View key (javni)", "view_key_public": "View key (javni)",
"view_transaction_on": "View Transaction on ", "view_transaction_on": "View Transaction on ",
"voting_weight": "Težina glasanja",
"waitFewSecondForTxUpdate": "Pričekajte nekoliko sekundi da se transakcija prikaže u povijesti transakcija", "waitFewSecondForTxUpdate": "Pričekajte nekoliko sekundi da se transakcija prikaže u povijesti transakcija",
"wallet_keys": "Pristupni izraz/ključ novčanika", "wallet_keys": "Pristupni izraz/ključ novčanika",
"wallet_list_create_new_wallet": "Izradi novi novčanik", "wallet_list_create_new_wallet": "Izradi novi novčanik",

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