From 55005f8b39b2b904507253227d1ff1cb7da5d86d Mon Sep 17 00:00:00 2001 From: OmarHatem <omarh.ismail1@gmail.com> Date: Wed, 8 Jan 2025 05:09:45 +0200 Subject: [PATCH 01/16] await settings migration --- lib/entities/default_settings_migration.dart | 30 +++++++++++++------- scripts/android/app_env.sh | 2 +- scripts/ios/app_env.sh | 2 +- scripts/linux/app_env.sh | 2 +- scripts/macos/app_env.sh | 2 +- 5 files changed, 24 insertions(+), 14 deletions(-) diff --git a/lib/entities/default_settings_migration.dart b/lib/entities/default_settings_migration.dart index 25140f106..90e32d982 100644 --- a/lib/entities/default_settings_migration.dart +++ b/lib/entities/default_settings_migration.dart @@ -70,8 +70,13 @@ Future<void> defaultSettingsMigration( await sharedPreferences.setBool(PreferencesKey.isNewInstall, isNewInstall); - final currentVersion = + int currentVersion = sharedPreferences.getInt(PreferencesKey.currentDefaultSettingsMigrationVersion) ?? 0; + // TODO: remove after v4.22.1 is live + /// for beta testers who didn't correctly get the 46 step configured + if (currentVersion == 46) { + currentVersion--; + } if (currentVersion >= version) { return; @@ -334,20 +339,20 @@ Future<void> defaultSettingsMigration( ); break; case 46: - _fixNodesUseSSLFlag(nodes); - updateWalletTypeNodesWithNewNode( + await _fixNodesUseSSLFlag(nodes); + await updateWalletTypeNodesWithNewNode( newNodeUri: 'litecoin.stackwallet.com:20063', nodes: nodes, type: WalletType.litecoin, useSSL: true, ); - updateWalletTypeNodesWithNewNode( + await updateWalletTypeNodesWithNewNode( newNodeUri: 'electrum-ltc.bysh.me:50002', nodes: nodes, type: WalletType.litecoin, useSSL: true, ); - _changeDefaultNode( + await _changeDefaultNode( nodes: nodes, sharedPreferences: sharedPreferences, type: WalletType.solana, @@ -360,13 +365,13 @@ Future<void> defaultSettingsMigration( 'solana-rpc.publicnode.com:443', ], ); - _updateNode( + await _updateNode( nodes: nodes, currentUri: "ethereum.publicnode.com", newUri: "ethereum-rpc.publicnode.com", useSSL: true, ); - _updateNode( + await _updateNode( nodes: nodes, currentUri: "polygon-bor.publicnode.com", newUri: "polygon-bor-rpc.publicnode.com", @@ -387,13 +392,16 @@ Future<void> defaultSettingsMigration( await sharedPreferences.setInt(PreferencesKey.currentDefaultSettingsMigrationVersion, version); } -void _updateNode({ +Future<void> _updateNode({ required Box<Node> nodes, required String currentUri, String? newUri, bool? useSSL, -}) { +}) async { for (Node node in nodes.values) { + print("@@@@@@@@@@@@@"); + print(node.uriRaw); + print(node.uri); if (node.uriRaw == currentUri) { if (newUri != null) { node.uriRaw = newUri; @@ -401,6 +409,7 @@ void _updateNode({ if (useSSL != null) { node.useSSL = useSSL; } + await node.save(); } } } @@ -481,7 +490,7 @@ void _deselectExchangeProvider(SharedPreferences sharedPreferences, String provi ); } -void _fixNodesUseSSLFlag(Box<Node> nodes) { +Future<void> _fixNodesUseSSLFlag(Box<Node> nodes) async { for (Node node in nodes.values) { switch (node.uriRaw) { case cakeWalletLitecoinElectrumUri: @@ -490,6 +499,7 @@ void _fixNodesUseSSLFlag(Box<Node> nodes) { case newCakeWalletMoneroUri: node.useSSL = true; node.trusted = true; + await node.save(); } } } diff --git a/scripts/android/app_env.sh b/scripts/android/app_env.sh index 6b1907451..45e28379d 100644 --- a/scripts/android/app_env.sh +++ b/scripts/android/app_env.sh @@ -23,7 +23,7 @@ MONERO_COM_SCHEME="monero.com" CAKEWALLET_NAME="Cake Wallet" CAKEWALLET_VERSION="4.22.1" -CAKEWALLET_BUILD_NUMBER=241 +CAKEWALLET_BUILD_NUMBER=242 CAKEWALLET_BUNDLE_ID="com.cakewallet.cake_wallet" CAKEWALLET_PACKAGE="com.cakewallet.cake_wallet" CAKEWALLET_SCHEME="cakewallet" diff --git a/scripts/ios/app_env.sh b/scripts/ios/app_env.sh index c1747c502..079b12391 100644 --- a/scripts/ios/app_env.sh +++ b/scripts/ios/app_env.sh @@ -19,7 +19,7 @@ MONERO_COM_BUNDLE_ID="com.cakewallet.monero" CAKEWALLET_NAME="Cake Wallet" CAKEWALLET_VERSION="4.22.1" -CAKEWALLET_BUILD_NUMBER=288 +CAKEWALLET_BUILD_NUMBER=289 CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet" HAVEN_NAME="Haven" diff --git a/scripts/linux/app_env.sh b/scripts/linux/app_env.sh index f0ec8e9e6..5103eeccc 100755 --- a/scripts/linux/app_env.sh +++ b/scripts/linux/app_env.sh @@ -15,7 +15,7 @@ fi CAKEWALLET_NAME="Cake Wallet" CAKEWALLET_VERSION="1.12.1" -CAKEWALLET_BUILD_NUMBER=42 +CAKEWALLET_BUILD_NUMBER=43 if ! [[ " ${TYPES[*]} " =~ " ${APP_LINUX_TYPE} " ]]; then echo "Wrong app type." diff --git a/scripts/macos/app_env.sh b/scripts/macos/app_env.sh index fe3d806d8..af2b6ab1e 100755 --- a/scripts/macos/app_env.sh +++ b/scripts/macos/app_env.sh @@ -22,7 +22,7 @@ MONERO_COM_BUNDLE_ID="com.cakewallet.monero" CAKEWALLET_NAME="Cake Wallet" CAKEWALLET_VERSION="1.15.1" -CAKEWALLET_BUILD_NUMBER=100 +CAKEWALLET_BUILD_NUMBER=101 CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet" if ! [[ " ${TYPES[*]} " =~ " ${APP_MACOS_TYPE} " ]]; then From eb2827402a1bccf1b938306099770b17e6483496 Mon Sep 17 00:00:00 2001 From: OmarHatem <omarh.ismail1@gmail.com> Date: Wed, 8 Jan 2025 05:12:57 +0200 Subject: [PATCH 02/16] revert beta testers change --- lib/entities/default_settings_migration.dart | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/lib/entities/default_settings_migration.dart b/lib/entities/default_settings_migration.dart index 90e32d982..abcdda4c0 100644 --- a/lib/entities/default_settings_migration.dart +++ b/lib/entities/default_settings_migration.dart @@ -70,13 +70,8 @@ Future<void> defaultSettingsMigration( await sharedPreferences.setBool(PreferencesKey.isNewInstall, isNewInstall); - int currentVersion = + final currentVersion = sharedPreferences.getInt(PreferencesKey.currentDefaultSettingsMigrationVersion) ?? 0; - // TODO: remove after v4.22.1 is live - /// for beta testers who didn't correctly get the 46 step configured - if (currentVersion == 46) { - currentVersion--; - } if (currentVersion >= version) { return; From b865e5e38bc5c154588147a4057f216899168c03 Mon Sep 17 00:00:00 2001 From: Kainoa Kanter <kainoakanter@gmail.com> Date: Sat, 11 Jan 2025 06:05:25 -0800 Subject: [PATCH 03/16] Closes #873 (#1928) --- .../mipmap-anydpi-v26/ic_launcher.xml | 1 + .../mipmap-hdpi/ic_launcher_adaptive_mono.png | Bin 0 -> 2359 bytes .../mipmap-mdpi/ic_launcher_adaptive_mono.png | Bin 0 -> 1544 bytes .../mipmap-xhdpi/ic_launcher_adaptive_mono.png | Bin 0 -> 3285 bytes .../mipmap-xxhdpi/ic_launcher_adaptive_mono.png | Bin 0 -> 5258 bytes .../mipmap-xxxhdpi/ic_launcher_adaptive_mono.png | Bin 0 -> 7640 bytes .../mipmap-anydpi-v26/ic_launcher.xml | 1 + .../mipmap-hdpi/ic_launcher_adaptive_mono.png | Bin 0 -> 2316 bytes .../mipmap-mdpi/ic_launcher_adaptive_mono.png | Bin 0 -> 1518 bytes .../mipmap-xhdpi/ic_launcher_adaptive_mono.png | Bin 0 -> 3110 bytes .../mipmap-xxhdpi/ic_launcher_adaptive_mono.png | Bin 0 -> 4880 bytes .../mipmap-xxxhdpi/ic_launcher_adaptive_mono.png | Bin 0 -> 6978 bytes 12 files changed, 2 insertions(+) create mode 100644 assets/images/cakewallet_android_icon/mipmap-hdpi/ic_launcher_adaptive_mono.png create mode 100644 assets/images/cakewallet_android_icon/mipmap-mdpi/ic_launcher_adaptive_mono.png create mode 100644 assets/images/cakewallet_android_icon/mipmap-xhdpi/ic_launcher_adaptive_mono.png create mode 100644 assets/images/cakewallet_android_icon/mipmap-xxhdpi/ic_launcher_adaptive_mono.png create mode 100644 assets/images/cakewallet_android_icon/mipmap-xxxhdpi/ic_launcher_adaptive_mono.png create mode 100644 assets/images/monerocom_android_icon/mipmap-hdpi/ic_launcher_adaptive_mono.png create mode 100644 assets/images/monerocom_android_icon/mipmap-mdpi/ic_launcher_adaptive_mono.png create mode 100644 assets/images/monerocom_android_icon/mipmap-xhdpi/ic_launcher_adaptive_mono.png create mode 100644 assets/images/monerocom_android_icon/mipmap-xxhdpi/ic_launcher_adaptive_mono.png create mode 100644 assets/images/monerocom_android_icon/mipmap-xxxhdpi/ic_launcher_adaptive_mono.png diff --git a/assets/images/cakewallet_android_icon/mipmap-anydpi-v26/ic_launcher.xml b/assets/images/cakewallet_android_icon/mipmap-anydpi-v26/ic_launcher.xml index 00d924171..c8bd4b26c 100644 --- a/assets/images/cakewallet_android_icon/mipmap-anydpi-v26/ic_launcher.xml +++ b/assets/images/cakewallet_android_icon/mipmap-anydpi-v26/ic_launcher.xml @@ -2,4 +2,5 @@ <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"> <background android:drawable="@mipmap/ic_launcher_adaptive_back"/> <foreground android:drawable="@mipmap/ic_launcher_adaptive_fore"/> + <monochrome android:drawable="@mipmap/ic_launcher_adaptive_mono"/> </adaptive-icon> \ No newline at end of file diff --git a/assets/images/cakewallet_android_icon/mipmap-hdpi/ic_launcher_adaptive_mono.png b/assets/images/cakewallet_android_icon/mipmap-hdpi/ic_launcher_adaptive_mono.png new file mode 100644 index 0000000000000000000000000000000000000000..27f939b416b899a04ebf6312ab9e99a322e3af8a GIT binary patch literal 2359 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 N2OAgbiZkB#{s!nGQz8HW literal 0 HcmV?d00001 diff --git a/assets/images/cakewallet_android_icon/mipmap-mdpi/ic_launcher_adaptive_mono.png b/assets/images/cakewallet_android_icon/mipmap-mdpi/ic_launcher_adaptive_mono.png new file mode 100644 index 0000000000000000000000000000000000000000..7bdb298c127e13a9b405704250496ca40f8c2eeb GIT binary patch literal 1544 zcmZ{kdpHw%7{`Az5$5vL!`yReJ5HK5*R0%TVhqDLxyHr_i?Kw~Rx0<1X<DvPO09@V zR4$Pdb33R=is+);N^)>GJI{HZbDqxgoIl?8`@HY_eBSRr@AIaST<m3~Riyy{vIGab zyGSGdiml?JjEE{ZAQCOAgS#^T$B_WA&j7G0YOy~6a1;%|OdtT*0s!FAg^h0eMFTO4 zlRX}6req77MU^Cz;A|)P5dwuuLOwX2d;oy>X9C`a96vhCiz0e@f)<v1fHp}g=&Xue z)&)9(ylXn0aQ_=*WL0;s?-4qmKPr^JzdE!Uc+>P=G$-kU2j6cw1?7ad>_0aW<79?u zwLZI~%~QOVz1iQC)bL(&F8SDelHZ;p{e8_}Ct~`{zt67k{a(CTIuK^8nsuQ3U*Y}k z9DJT-l}ypBII~Z0Czpt9AX+_SG74m>rvJFmgSAAQn@~W0e3P{6DapTogyaZ?YvkwJ z%17ngX>9pOYI8yU#<|;u7^juZoNlUN^D~9+UDEI4<9eIpOE|H@N{-^AtJZ>cVsYq- zv;YQksr3`27H#z<h?j;0q8+lri+<+MLI{^85{Ge0^Ac48ZsafyxkqAo8_&nQ>MYUA zkmq%3d%L-vS##67C^;v(f2Wk|RZGi?b1$ciF72K+f23up8|rbeu5{eCst9|V5pP<8 zDwL<vTMeI=4Tc0DXBK5-4l5iA3**7q76v{VoURkz<k})rmu=-4UgPEI#7m7ASufy7 zzM=tt!Zqf>NsFk(&~)|6g!~A*Vt1wM7i($<-9G6h==7=fHVn;RG)X8-o>(U>k-g8Z zxQBS$*g*G|2g<PM7j>B?x2YE#uTG2ByeiM!k@uv2D5a_yJNuMYm`Ls>Ug#;c#XJW& zwyr!Mn#XqD(QJE-%g|W4b*uz~(yr_fF2!>48B@_Zkf{xuA<KA2#wa9iXX_;?*MWr` zq8f6CUa;Sj-B2ASC7LA2>5!AG$p_>#+5}Q7*$U4y=?>5T28YZ&ZqaJ>w}B75ep%G0 zOjU=x!GJ6KWp}Q)RG6lJGMj8vgI?dF)izVwvCh~TlB5B@@r-m+k*zvFeWm9P&)_aH zw2}=j+_Mqn5@wz{UUsn9y>=a^m0|<qK^hd<rZ9utEn|C1=u4h*@b!o3H|%HMPVx}3 z!(xx?#128+;=lr;zfHM1z)~&OraCc8gM(Rv#GhhFvv+Odh&dGmLvw;Y&Bkr<$FodK zIflzLhJ`NG%T3&PpzC#ugw8F=-n%7Af%nxtaZ&x0jW8E)YB@#c3lDX~2uxcm!O<)E zsSPRg`V-nJFxJ#)HmX*Z#k$x>&M1gs?5N4YJqf<7qP!8%@m6lp6-1MlLV@C#!Ny%x z>4=rOuKJe2c5Bhr1y%iLBa`(YryIdwxldj4vDn~Bi*7HVd~K`MuLZVXKegKff;ZQn zw{qiCD?4n2yllm<+*AVEVa#;NL>X~pt+OykMyjkOQR0tODu48G!o?~t0?kb|LQ_7r z*Y;*clV^soou1z{>KZ^Sf7{i$b4P4)cpABZudi91WS0M#7U{F9P}02t>v}=+wU$lQ zAL$*p6;OSCavea;f4NbSsdHDkj2m|{m~@RlZS-Y@mzB8%^`2{(Em-5yYT}}*xqibq zkD)|kx!ED?T>X^uOFAY@#`ST@_{Iy#p=!J(buN3>vBrwFAd^AX_ZA+pukEJV50)nD z3_B{d&e^CHUcn1;JNBJQS6Pa^6OPC$?Mui^2`#4-7Yi{`GrNbShjomkCYOA}cx%D$ zJ|@`ZB_y;BQR+iaLl2enoP-`@N#}8SOn0kel?|JBV!wBc;SAiKqz$^tzfy1X>3bFN zpAVzj<N1Wub5BWZxqttp=oKQEb_bckLCg>=H6}zPzz}U{f<j|ZXd^P(5Nl+N#hB`& z(O5M4ox)q#4*)$X_%JQu{{gPEZ?y=}`^SNKm>v?#45CN>z!+iCW>_@lZxfo5^@@lA N1Unb}ZCv2#KLH{Bp9lZ| literal 0 HcmV?d00001 diff --git a/assets/images/cakewallet_android_icon/mipmap-xhdpi/ic_launcher_adaptive_mono.png b/assets/images/cakewallet_android_icon/mipmap-xhdpi/ic_launcher_adaptive_mono.png new file mode 100644 index 0000000000000000000000000000000000000000..79e9df08d83daea66bec94b669062a82b6603e4f GIT binary patch literal 3285 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 B0Pp|+ literal 0 HcmV?d00001 diff --git a/assets/images/cakewallet_android_icon/mipmap-xxhdpi/ic_launcher_adaptive_mono.png b/assets/images/cakewallet_android_icon/mipmap-xxhdpi/ic_launcher_adaptive_mono.png new file mode 100644 index 0000000000000000000000000000000000000000..0bb1c74308757dc2319eb2a63bbcc81cab2fd95c GIT binary patch literal 5258 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 K2WU;ZsQ&`>vhJP$ literal 0 HcmV?d00001 diff --git a/assets/images/cakewallet_android_icon/mipmap-xxxhdpi/ic_launcher_adaptive_mono.png b/assets/images/cakewallet_android_icon/mipmap-xxxhdpi/ic_launcher_adaptive_mono.png new file mode 100644 index 0000000000000000000000000000000000000000..205f2ad2a5ab1a7a704a5b3bbab36249aeb2be4f GIT binary patch literal 7640 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 Kx#E>o_<sRfUWo?) literal 0 HcmV?d00001 diff --git a/assets/images/monerocom_android_icon/mipmap-anydpi-v26/ic_launcher.xml b/assets/images/monerocom_android_icon/mipmap-anydpi-v26/ic_launcher.xml index 00d924171..c8bd4b26c 100644 --- a/assets/images/monerocom_android_icon/mipmap-anydpi-v26/ic_launcher.xml +++ b/assets/images/monerocom_android_icon/mipmap-anydpi-v26/ic_launcher.xml @@ -2,4 +2,5 @@ <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"> <background android:drawable="@mipmap/ic_launcher_adaptive_back"/> <foreground android:drawable="@mipmap/ic_launcher_adaptive_fore"/> + <monochrome android:drawable="@mipmap/ic_launcher_adaptive_mono"/> </adaptive-icon> \ No newline at end of file diff --git a/assets/images/monerocom_android_icon/mipmap-hdpi/ic_launcher_adaptive_mono.png b/assets/images/monerocom_android_icon/mipmap-hdpi/ic_launcher_adaptive_mono.png new file mode 100644 index 0000000000000000000000000000000000000000..af8126ea9fd3293c46c1c46dd153d14a251b55e9 GIT binary patch literal 2316 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 T{Ve?DfB~Q{U@dCQ2{--%6Z0WK literal 0 HcmV?d00001 diff --git a/assets/images/monerocom_android_icon/mipmap-mdpi/ic_launcher_adaptive_mono.png b/assets/images/monerocom_android_icon/mipmap-mdpi/ic_launcher_adaptive_mono.png new file mode 100644 index 0000000000000000000000000000000000000000..0778b841f126a4fbccd94eaffa1e7a90a83b0215 GIT binary patch literal 1518 zcmZ{kdpOez7{`BdOXiwzDzToV)y6JO$B0};6Dql6sqALWY=$kQ4#f#`Qbvl*CB$MK zSqi6%I?8coB$`>)#bvVMkS@~V>^$dr&hz-=JkR^S-}mx--uJ&ZXJ3$?(W<qp001z; z?e+=QXzV|}Qb!Z*<H~(CVn^B?90&j>HUmI<CIBpGTIp{AfCC2rRTKbVE(3rStF&#u zn`W?rxW~^2Sjsxz{XkRcvvGk~{YfotZG9W{o{e(=pz{pp;~A1HpDJM-3#F`YPn*Li zl)GV^+mST^;bF0@NGq4V=7jwj{@@cC{@E24nKvuk>pWji)aizieJ*5X;=Bhay2dul zwG!uHHbba%lrUWGG+*k^`c|6ws>kKa^mJsIw>qsiOZ2UDqHL$f;)I*iQlh7+&N7=% zE67*A>#fQpa$5>0P@>}~=&7H>)b_rIx0v5UT8eGfQ&#?dQ~huv1hqHGkNW7uePTBj z(xfxgyGmgbbe1!K;#U_&Jej{R-sU>}#7lL#w6ZWlFD2KdP4_*db{iHVQtvv=%sGgZ zNjjj-Ake~4!y$VfV4Gq`agTGFlp4@&J_d-}U(*#{VC1}vBy4TF=rxdhos%7)={P&M z+}-;Oi=wvdDi=d1)(Ibf+!PW+avFzb&r5^LuIBx;4pu&#ITNu$U@KrnMpI|E^7r=^ z?Y*jNf*9YpW~?<cH7oYBV5oP;4sbifO6bcJ$#u6-onFP~<(7`a;|{E?yqoXtfi-k) z1+D08pl;3ON8Y5(8akQpW2{nF>%PLo@NeJx^H|ckn0#hV@&}vnv*E3w%_%?6>ST!R zF1BHbLzA*0DpW{5P9eqi3C+*-x5oz<8Bz?YC`DRfsv?5|ah>-LTRpqn<DiAZs1160 zJAWavkW-MFY60u*F_CJ-5d^|-Aw9*`UqOSSqGqa@-~xs5VWE~?h2DI0R0e6F4MNT{ zr$2>}6WS|9?*JM3u}MXDnDEN;sGPu*@>+k`DdJMgd6rf>w@&VR8)?zslm(0AsvcJ@ znu<ljdyg#AxreIpp@n#pHSCUCkk47N6))r!7-c7)R?Q{s*@nS`-FmlP+ick=<cD-N z)X9lOruV^;V`~!pLh57FvIFJPl8E_rD(kfigRDqF=xjYV3~U5Fw=kXU(Q)I2)bT*) z2F~_@n;pU1_V;0axMcmk-<Fs*B)t)gpmSYG*8|PC(y4e@PYSFEU-YJlF?G_Prjy4q z0S+T#&YO|Z4jZphW{g^`txIR{Q1nao<%%z|TM8zhLC{u6YxUWCWV6{B2Y-_Y@9i8p zIp(`rLKFz=MJsvqRHcDRD|t|r>~12zt<IsVeyuvmJJMA=bI-fGr_N>CagcM0{FQIt zM%g&@M%FhNnk&RH&`Y0xLZDqOU76@Cp+%tmpt-M@icc5US2@$KAHimj>S@N08{AJm z`tI0OVoCpA?uo7)K|Wc%o>0Z9LArlh^fME6Ij>jJIurS^qjx_E(*3y+LB@lVHN~US zAfRjla2XIu@T8at=HMGbAztaw;<e!@ekv_GpIHh2wi;x7DOp1JOYiIZ++y<*^;|cl zzl62RcFgd|wLiEo0}GpSPb@amQu{m}^g)!qyw$T7-XBpsJC9*pCDXpZD)JRia`$6G zxh79?TZ3BJbmR`NE47S!?n8@aeRG-Of;J)rH{~X7)W<U#p2N)dno+6tXo;t#s;JSS zKwda{yf{XoNTTX;a7(dLXt)6Em(*EMkXrt7Q%%p@S?`jEwdCL~eYNsOd|qP7&cf<< zjOc}<JY~ESJ)#RXW*&8hurOJ1F>Dd{ZOL-^D=~fT(Sd02zY@@OTJ!Mi+1P_@GJ#FO zkP;{w0g!Mc8U{ze;HVHd5`)@~K{#)N!!dBU(sUHG3}D2OY0)YF4_pd7)TjZr{C9y( kV^9*=1O{svgTlafV302V9<drW7|}2Q4jbfi!z=2{-waEq(f|Me literal 0 HcmV?d00001 diff --git a/assets/images/monerocom_android_icon/mipmap-xhdpi/ic_launcher_adaptive_mono.png b/assets/images/monerocom_android_icon/mipmap-xhdpi/ic_launcher_adaptive_mono.png new file mode 100644 index 0000000000000000000000000000000000000000..318914c59e86df6fe1f898925bdbb089682b5461 GIT binary patch literal 3110 zcmb7`X*3jU8^@<8%AR!?m1LQSF(Wb<J6S7Rwi#rLY0CD9&|?YN21ByUP?nHwEHhb? zBt{rgjG3shj4~m5vW8dhbIyCt^WpvQe7LXwxv%^D&UK&vhx`5~U$HUcJ1%(~008ir zUoy5mP}=Xs&3RB|!SlWca@y;Xtu+8}R~`U}xeowrAGBh=004hL0Dwgg005o`0Eh?T z+pg*y92~xGX=V)APs$kVI@ocAnp>N2eLcj%!6p66^2`qafakcmv4MR!eTfhmDEdLV zPftc>&IclRg=i!4?6e2TkzHM)=pZCo?9c!&B{^u1xg04YTy<q{KDa	~P-ja}XlY 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 literal 0 HcmV?d00001 diff --git a/assets/images/monerocom_android_icon/mipmap-xxhdpi/ic_launcher_adaptive_mono.png b/assets/images/monerocom_android_icon/mipmap-xxhdpi/ic_launcher_adaptive_mono.png new file mode 100644 index 0000000000000000000000000000000000000000..b1165abe85ed60d39f44a52b3bccb09a7c8f50ea GIT binary patch literal 4880 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 A&;S4c literal 0 HcmV?d00001 diff --git a/assets/images/monerocom_android_icon/mipmap-xxxhdpi/ic_launcher_adaptive_mono.png b/assets/images/monerocom_android_icon/mipmap-xxxhdpi/ic_launcher_adaptive_mono.png new file mode 100644 index 0000000000000000000000000000000000000000..ea11a01d31ea2f0a00bf72409a2fe79103aa1186 GIT binary patch literal 6978 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 X|Jw=OGV%JI3_wFgN4ZYXI{g0tJY&B* literal 0 HcmV?d00001 From 82b65e8934f6e31ef945a13b9295c42a3c207218 Mon Sep 17 00:00:00 2001 From: cyan <cyjan@mrcyjanek.net> Date: Sat, 11 Jan 2025 21:35:45 +0100 Subject: [PATCH 04/16] Fix normal wallets showing export outputs QR code (#1952) --- cw_monero/lib/monero_wallet.dart | 3 + ios/Podfile.lock | 100 +++++------------- linux/flutter/generated_plugins.cmake | 1 - macos/Flutter/GeneratedPluginRegistrant.swift | 2 - windows/flutter/generated_plugins.cmake | 1 - 5 files changed, 28 insertions(+), 79 deletions(-) diff --git a/cw_monero/lib/monero_wallet.dart b/cw_monero/lib/monero_wallet.dart index b46e8dd10..af943b9e1 100644 --- a/cw_monero/lib/monero_wallet.dart +++ b/cw_monero/lib/monero_wallet.dart @@ -265,6 +265,9 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance, } bool needExportOutputs(int amount) { + if (int.tryParse(monero.Wallet_secretSpendKey(wptr!)) != 0) { + return false; + } // viewOnlyBalance - balance that we can spend // TODO(mrcyjanek): remove hasUnknownKeyImages when we cleanup coin control return (monero.Wallet_viewOnlyBalance(wptr!, diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 9e2a8507a..5b80a86e8 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -3,38 +3,6 @@ PODS: - Flutter - ReachabilitySwift - CryptoSwift (1.8.3) - - cw_haven (0.0.1): - - cw_haven/Boost (= 0.0.1) - - cw_haven/Haven (= 0.0.1) - - cw_haven/OpenSSL (= 0.0.1) - - cw_haven/Sodium (= 0.0.1) - - cw_shared_external - - Flutter - - cw_haven/Boost (0.0.1): - - cw_shared_external - - Flutter - - cw_haven/Haven (0.0.1): - - cw_shared_external - - Flutter - - cw_haven/OpenSSL (0.0.1): - - cw_shared_external - - Flutter - - cw_haven/Sodium (0.0.1): - - cw_shared_external - - Flutter - - cw_mweb (0.0.1): - - Flutter - - cw_shared_external (0.0.1): - - cw_shared_external/Boost (= 0.0.1) - - cw_shared_external/OpenSSL (= 0.0.1) - - cw_shared_external/Sodium (= 0.0.1) - - Flutter - - cw_shared_external/Boost (0.0.1): - - Flutter - - cw_shared_external/OpenSSL (0.0.1): - - Flutter - - cw_shared_external/Sodium (0.0.1): - - Flutter - device_display_brightness (0.0.1): - Flutter - device_info_plus (0.0.1): @@ -117,8 +85,6 @@ PODS: - shared_preferences_foundation (0.0.1): - Flutter - FlutterMacOS - - sp_scanner (0.0.1): - - Flutter - SwiftyGif (5.4.5) - Toast (4.1.1) - uni_links (0.0.1): @@ -136,9 +102,6 @@ PODS: DEPENDENCIES: - connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`) - CryptoSwift - - cw_haven (from `.symlinks/plugins/cw_haven/ios`) - - cw_mweb (from `.symlinks/plugins/cw_mweb/ios`) - - cw_shared_external (from `.symlinks/plugins/cw_shared_external/ios`) - device_display_brightness (from `.symlinks/plugins/device_display_brightness/ios`) - device_info_plus (from `.symlinks/plugins/device_info_plus/ios`) - devicelocale (from `.symlinks/plugins/devicelocale/ios`) @@ -158,7 +121,6 @@ DEPENDENCIES: - sensitive_clipboard (from `.symlinks/plugins/sensitive_clipboard/ios`) - share_plus (from `.symlinks/plugins/share_plus/ios`) - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`) - - sp_scanner (from `.symlinks/plugins/sp_scanner/ios`) - uni_links (from `.symlinks/plugins/uni_links/ios`) - universal_ble (from `.symlinks/plugins/universal_ble/darwin`) - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) @@ -179,12 +141,6 @@ SPEC REPOS: EXTERNAL SOURCES: connectivity_plus: :path: ".symlinks/plugins/connectivity_plus/ios" - cw_haven: - :path: ".symlinks/plugins/cw_haven/ios" - cw_mweb: - :path: ".symlinks/plugins/cw_mweb/ios" - cw_shared_external: - :path: ".symlinks/plugins/cw_shared_external/ios" device_display_brightness: :path: ".symlinks/plugins/device_display_brightness/ios" device_info_plus: @@ -223,8 +179,6 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/share_plus/ios" shared_preferences_foundation: :path: ".symlinks/plugins/shared_preferences_foundation/darwin" - sp_scanner: - :path: ".symlinks/plugins/sp_scanner/ios" uni_links: :path: ".symlinks/plugins/uni_links/ios" universal_ble: @@ -237,44 +191,40 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/workmanager/ios" SPEC CHECKSUMS: - connectivity_plus: bf0076dd84a130856aa636df1c71ccaff908fa1d + connectivity_plus: 481668c94744c30c53b8895afb39159d1e619bdf CryptoSwift: 967f37cea5a3294d9cce358f78861652155be483 - cw_haven: b3e54e1fbe7b8e6fda57a93206bc38f8e89b898a - cw_mweb: 87af74f9659fed0c1a2cbfb44413f1070e79e3ae - cw_shared_external: 2972d872b8917603478117c9957dfca611845a92 - device_display_brightness: 1510e72c567a1f6ce6ffe393dcd9afd1426034f7 - device_info_plus: c6fb39579d0f423935b0c9ce7ee2f44b71b9fce6 - devicelocale: 35ba84dc7f45f527c3001535d8c8d104edd5d926 + device_display_brightness: 04374ebd653619292c1d996f00f42877ea19f17f + device_info_plus: 335f3ce08d2e174b9fdc3db3db0f4e3b1f66bd89 + devicelocale: bd64aa714485a8afdaded0892c1e7d5b7f680cf8 DKImagePickerController: 946cec48c7873164274ecc4624d19e3da4c1ef3c DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60 - fast_scanner: 44c00940355a51258cd6c2085734193cd23d95bc - file_picker: 15fd9539e4eb735dc54bae8c0534a7a9511a03de + fast_scanner: 2cb1ad3e69e645e9980fb4961396ce5804caa3e3 + file_picker: 07c75322ede1d47ec9bb4ac82b27c94d3598251a Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 - flutter_inappwebview_ios: 6f63631e2c62a7c350263b13fa5427aedefe81d4 - flutter_local_authentication: 1172a4dd88f6306dadce067454e2c4caf07977bb - flutter_mailer: 2ef5a67087bc8c6c4cefd04a178bf1ae2c94cd83 - flutter_secure_storage: 23fc622d89d073675f2eaa109381aefbcf5a49be - fluttertoast: e9a18c7be5413da53898f660530c56f35edfba9c - in_app_review: a31b5257259646ea78e0e35fc914979b0031d011 - integration_test: 252f60fa39af5e17c3aa9899d35d908a0721b573 + flutter_inappwebview_ios: b89ba3482b96fb25e00c967aae065701b66e9b99 + flutter_local_authentication: 989278c681612f1ee0e36019e149137f114b9d7f + flutter_mailer: 3a8cd4f36c960fb04528d5471097270c19fec1c4 + flutter_secure_storage: 2c2ff13db9e0a5647389bff88b0ecac56e3f3418 + fluttertoast: 76fea30fcf04176325f6864c87306927bd7d2038 + in_app_review: 5596fe56fab799e8edb3561c03d053363ab13457 + integration_test: 4a889634ef21a45d28d50d622cf412dc6d9f586e OrderedSet: e539b66b644ff081c73a262d24ad552a69be3a94 - package_info_plus: c0502532a26c7662a62a356cebe2692ec5fe4ec4 - path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46 - permission_handler_apple: e76247795d700c14ea09e3a2d8855d41ee80a2e6 + package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499 + path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564 + permission_handler_apple: 3787117e48f80715ff04a3830ca039283d6a4f29 ReachabilitySwift: 32793e867593cfc1177f5d16491e3a197d2fccda SDWebImage: 8a6b7b160b4d710e2a22b6900e25301075c34cb3 - sensitive_clipboard: d4866e5d176581536c27bb1618642ee83adca986 - share_plus: 8b6f8b3447e494cca5317c8c3073de39b3600d1f - shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78 - sp_scanner: eaa617fa827396b967116b7f1f43549ca62e9a12 + sensitive_clipboard: 161e9abc3d56b3131309d8a321eb4690a803c16b + share_plus: 50da8cb520a8f0f65671c6c6a99b3617ed10a58a + shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7 SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4 Toast: 1f5ea13423a1e6674c4abdac5be53587ae481c4e - uni_links: d97da20c7701486ba192624d99bffaaffcfc298a - universal_ble: cf52a7b3fd2e7c14d6d7262e9fdadb72ab6b88a6 - url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe - wakelock_plus: 373cfe59b235a6dd5837d0fb88791d2f13a90d56 - workmanager: 0afdcf5628bbde6924c21af7836fed07b42e30e6 + uni_links: ed8c961e47ed9ce42b6d91e1de8049e38a4b3152 + universal_ble: ff19787898040d721109c6324472e5dd4bc86adc + url_launcher_ios: 694010445543906933d732453a59da0a173ae33d + wakelock_plus: 04623e3f525556020ebd4034310f20fe7fda8b49 + workmanager: 01be2de7f184bd15de93a1812936a2b7f42ef07e PODFILE CHECKSUM: e448f662d4c41f0c0b1ccbb78afd57dbf895a597 -COCOAPODS: 1.15.2 +COCOAPODS: 1.16.2 diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake index f52be7481..4b9eb3b2d 100644 --- a/linux/flutter/generated_plugins.cmake +++ b/linux/flutter/generated_plugins.cmake @@ -10,7 +10,6 @@ list(APPEND FLUTTER_PLUGIN_LIST ) list(APPEND FLUTTER_FFI_PLUGIN_LIST - sp_scanner ) set(PLUGIN_BUNDLED_LIBRARIES) diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 42b9fa84c..52b44e53e 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -6,7 +6,6 @@ import FlutterMacOS import Foundation import connectivity_plus -import cw_mweb import device_info_plus import devicelocale import fast_scanner @@ -24,7 +23,6 @@ import wakelock_plus func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { ConnectivityPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlugin")) - CwMwebPlugin.register(with: registry.registrar(forPlugin: "CwMwebPlugin")) DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin")) DevicelocalePlugin.register(with: registry.registrar(forPlugin: "DevicelocalePlugin")) MobileScannerPlugin.register(with: registry.registrar(forPlugin: "MobileScannerPlugin")) diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index e0f2c11c0..f8f89611c 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -14,7 +14,6 @@ list(APPEND FLUTTER_PLUGIN_LIST ) list(APPEND FLUTTER_FFI_PLUGIN_LIST - sp_scanner ) set(PLUGIN_BUNDLED_LIBRARIES) From e42d49f3edd5082f88cf3301486373215eab00bf Mon Sep 17 00:00:00 2001 From: cyan <cyjan@mrcyjanek.net> Date: Sat, 11 Jan 2025 21:36:41 +0100 Subject: [PATCH 05/16] fix print in default_settings_migration (#1953) * fix print in default_settings_migration * Update lib/entities/default_settings_migration.dart [skip ci] --------- Co-authored-by: Omar Hatem <omarh.ismail1@gmail.com> --- lib/entities/default_settings_migration.dart | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/entities/default_settings_migration.dart b/lib/entities/default_settings_migration.dart index abcdda4c0..049bfa15c 100644 --- a/lib/entities/default_settings_migration.dart +++ b/lib/entities/default_settings_migration.dart @@ -394,9 +394,6 @@ Future<void> _updateNode({ bool? useSSL, }) async { for (Node node in nodes.values) { - print("@@@@@@@@@@@@@"); - print(node.uriRaw); - print(node.uri); if (node.uriRaw == currentUri) { if (newUri != null) { node.uriRaw = newUri; From 206c7159c21e63c67430f8063f58a5fb5b6a3650 Mon Sep 17 00:00:00 2001 From: OmarHatem <omarh.ismail1@gmail.com> Date: Mon, 13 Jan 2025 13:06:43 +0200 Subject: [PATCH 06/16] minor fix [skip ci] --- ios/Podfile.lock | 100 +++++++++++++----- lib/src/screens/send/send_page.dart | 4 + linux/flutter/generated_plugins.cmake | 1 + macos/Flutter/GeneratedPluginRegistrant.swift | 2 + windows/flutter/generated_plugins.cmake | 1 + 5 files changed, 83 insertions(+), 25 deletions(-) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 5b80a86e8..9e2a8507a 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -3,6 +3,38 @@ PODS: - Flutter - ReachabilitySwift - CryptoSwift (1.8.3) + - cw_haven (0.0.1): + - cw_haven/Boost (= 0.0.1) + - cw_haven/Haven (= 0.0.1) + - cw_haven/OpenSSL (= 0.0.1) + - cw_haven/Sodium (= 0.0.1) + - cw_shared_external + - Flutter + - cw_haven/Boost (0.0.1): + - cw_shared_external + - Flutter + - cw_haven/Haven (0.0.1): + - cw_shared_external + - Flutter + - cw_haven/OpenSSL (0.0.1): + - cw_shared_external + - Flutter + - cw_haven/Sodium (0.0.1): + - cw_shared_external + - Flutter + - cw_mweb (0.0.1): + - Flutter + - cw_shared_external (0.0.1): + - cw_shared_external/Boost (= 0.0.1) + - cw_shared_external/OpenSSL (= 0.0.1) + - cw_shared_external/Sodium (= 0.0.1) + - Flutter + - cw_shared_external/Boost (0.0.1): + - Flutter + - cw_shared_external/OpenSSL (0.0.1): + - Flutter + - cw_shared_external/Sodium (0.0.1): + - Flutter - device_display_brightness (0.0.1): - Flutter - device_info_plus (0.0.1): @@ -85,6 +117,8 @@ PODS: - shared_preferences_foundation (0.0.1): - Flutter - FlutterMacOS + - sp_scanner (0.0.1): + - Flutter - SwiftyGif (5.4.5) - Toast (4.1.1) - uni_links (0.0.1): @@ -102,6 +136,9 @@ PODS: DEPENDENCIES: - connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`) - CryptoSwift + - cw_haven (from `.symlinks/plugins/cw_haven/ios`) + - cw_mweb (from `.symlinks/plugins/cw_mweb/ios`) + - cw_shared_external (from `.symlinks/plugins/cw_shared_external/ios`) - device_display_brightness (from `.symlinks/plugins/device_display_brightness/ios`) - device_info_plus (from `.symlinks/plugins/device_info_plus/ios`) - devicelocale (from `.symlinks/plugins/devicelocale/ios`) @@ -121,6 +158,7 @@ DEPENDENCIES: - sensitive_clipboard (from `.symlinks/plugins/sensitive_clipboard/ios`) - share_plus (from `.symlinks/plugins/share_plus/ios`) - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`) + - sp_scanner (from `.symlinks/plugins/sp_scanner/ios`) - uni_links (from `.symlinks/plugins/uni_links/ios`) - universal_ble (from `.symlinks/plugins/universal_ble/darwin`) - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) @@ -141,6 +179,12 @@ SPEC REPOS: EXTERNAL SOURCES: connectivity_plus: :path: ".symlinks/plugins/connectivity_plus/ios" + cw_haven: + :path: ".symlinks/plugins/cw_haven/ios" + cw_mweb: + :path: ".symlinks/plugins/cw_mweb/ios" + cw_shared_external: + :path: ".symlinks/plugins/cw_shared_external/ios" device_display_brightness: :path: ".symlinks/plugins/device_display_brightness/ios" device_info_plus: @@ -179,6 +223,8 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/share_plus/ios" shared_preferences_foundation: :path: ".symlinks/plugins/shared_preferences_foundation/darwin" + sp_scanner: + :path: ".symlinks/plugins/sp_scanner/ios" uni_links: :path: ".symlinks/plugins/uni_links/ios" universal_ble: @@ -191,40 +237,44 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/workmanager/ios" SPEC CHECKSUMS: - connectivity_plus: 481668c94744c30c53b8895afb39159d1e619bdf + connectivity_plus: bf0076dd84a130856aa636df1c71ccaff908fa1d CryptoSwift: 967f37cea5a3294d9cce358f78861652155be483 - device_display_brightness: 04374ebd653619292c1d996f00f42877ea19f17f - device_info_plus: 335f3ce08d2e174b9fdc3db3db0f4e3b1f66bd89 - devicelocale: bd64aa714485a8afdaded0892c1e7d5b7f680cf8 + cw_haven: b3e54e1fbe7b8e6fda57a93206bc38f8e89b898a + cw_mweb: 87af74f9659fed0c1a2cbfb44413f1070e79e3ae + cw_shared_external: 2972d872b8917603478117c9957dfca611845a92 + device_display_brightness: 1510e72c567a1f6ce6ffe393dcd9afd1426034f7 + device_info_plus: c6fb39579d0f423935b0c9ce7ee2f44b71b9fce6 + devicelocale: 35ba84dc7f45f527c3001535d8c8d104edd5d926 DKImagePickerController: 946cec48c7873164274ecc4624d19e3da4c1ef3c DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60 - fast_scanner: 2cb1ad3e69e645e9980fb4961396ce5804caa3e3 - file_picker: 07c75322ede1d47ec9bb4ac82b27c94d3598251a + fast_scanner: 44c00940355a51258cd6c2085734193cd23d95bc + file_picker: 15fd9539e4eb735dc54bae8c0534a7a9511a03de Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 - flutter_inappwebview_ios: b89ba3482b96fb25e00c967aae065701b66e9b99 - flutter_local_authentication: 989278c681612f1ee0e36019e149137f114b9d7f - flutter_mailer: 3a8cd4f36c960fb04528d5471097270c19fec1c4 - flutter_secure_storage: 2c2ff13db9e0a5647389bff88b0ecac56e3f3418 - fluttertoast: 76fea30fcf04176325f6864c87306927bd7d2038 - in_app_review: 5596fe56fab799e8edb3561c03d053363ab13457 - integration_test: 4a889634ef21a45d28d50d622cf412dc6d9f586e + flutter_inappwebview_ios: 6f63631e2c62a7c350263b13fa5427aedefe81d4 + flutter_local_authentication: 1172a4dd88f6306dadce067454e2c4caf07977bb + flutter_mailer: 2ef5a67087bc8c6c4cefd04a178bf1ae2c94cd83 + flutter_secure_storage: 23fc622d89d073675f2eaa109381aefbcf5a49be + fluttertoast: e9a18c7be5413da53898f660530c56f35edfba9c + in_app_review: a31b5257259646ea78e0e35fc914979b0031d011 + integration_test: 252f60fa39af5e17c3aa9899d35d908a0721b573 OrderedSet: e539b66b644ff081c73a262d24ad552a69be3a94 - package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499 - path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564 - permission_handler_apple: 3787117e48f80715ff04a3830ca039283d6a4f29 + package_info_plus: c0502532a26c7662a62a356cebe2692ec5fe4ec4 + path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46 + permission_handler_apple: e76247795d700c14ea09e3a2d8855d41ee80a2e6 ReachabilitySwift: 32793e867593cfc1177f5d16491e3a197d2fccda SDWebImage: 8a6b7b160b4d710e2a22b6900e25301075c34cb3 - sensitive_clipboard: 161e9abc3d56b3131309d8a321eb4690a803c16b - share_plus: 50da8cb520a8f0f65671c6c6a99b3617ed10a58a - shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7 + sensitive_clipboard: d4866e5d176581536c27bb1618642ee83adca986 + share_plus: 8b6f8b3447e494cca5317c8c3073de39b3600d1f + shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78 + sp_scanner: eaa617fa827396b967116b7f1f43549ca62e9a12 SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4 Toast: 1f5ea13423a1e6674c4abdac5be53587ae481c4e - uni_links: ed8c961e47ed9ce42b6d91e1de8049e38a4b3152 - universal_ble: ff19787898040d721109c6324472e5dd4bc86adc - url_launcher_ios: 694010445543906933d732453a59da0a173ae33d - wakelock_plus: 04623e3f525556020ebd4034310f20fe7fda8b49 - workmanager: 01be2de7f184bd15de93a1812936a2b7f42ef07e + uni_links: d97da20c7701486ba192624d99bffaaffcfc298a + universal_ble: cf52a7b3fd2e7c14d6d7262e9fdadb72ab6b88a6 + url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe + wakelock_plus: 373cfe59b235a6dd5837d0fb88791d2f13a90d56 + workmanager: 0afdcf5628bbde6924c21af7836fed07b42e30e6 PODFILE CHECKSUM: e448f662d4c41f0c0b1ccbb78afd57dbf895a597 -COCOAPODS: 1.16.2 +COCOAPODS: 1.15.2 diff --git a/lib/src/screens/send/send_page.dart b/lib/src/screens/send/send_page.dart index a52bd11e9..2d64c55a3 100644 --- a/lib/src/screens/send/send_page.dart +++ b/lib/src/screens/send/send_page.dart @@ -525,6 +525,10 @@ class SendPage extends BasePage { if (state is TransactionCommitted) { WidgetsBinding.instance.addPostFrameCallback((_) async { + if (!context.mounted) { + return; + } + final successMessage = S.of(context).send_success( sendViewModel.selectedCryptoCurrency.toString()); diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake index 4b9eb3b2d..f52be7481 100644 --- a/linux/flutter/generated_plugins.cmake +++ b/linux/flutter/generated_plugins.cmake @@ -10,6 +10,7 @@ list(APPEND FLUTTER_PLUGIN_LIST ) list(APPEND FLUTTER_FFI_PLUGIN_LIST + sp_scanner ) set(PLUGIN_BUNDLED_LIBRARIES) diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 52b44e53e..42b9fa84c 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -6,6 +6,7 @@ import FlutterMacOS import Foundation import connectivity_plus +import cw_mweb import device_info_plus import devicelocale import fast_scanner @@ -23,6 +24,7 @@ import wakelock_plus func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { ConnectivityPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlugin")) + CwMwebPlugin.register(with: registry.registrar(forPlugin: "CwMwebPlugin")) DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin")) DevicelocalePlugin.register(with: registry.registrar(forPlugin: "DevicelocalePlugin")) MobileScannerPlugin.register(with: registry.registrar(forPlugin: "MobileScannerPlugin")) diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index f8f89611c..e0f2c11c0 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -14,6 +14,7 @@ list(APPEND FLUTTER_PLUGIN_LIST ) list(APPEND FLUTTER_FFI_PLUGIN_LIST + sp_scanner ) set(PLUGIN_BUNDLED_LIBRARIES) From 80b116b8ae31bb86830aca1fa50192919a0bb2af Mon Sep 17 00:00:00 2001 From: hidewrong <hidewrong@outlook.com> Date: Tue, 14 Jan 2025 22:34:53 +0800 Subject: [PATCH 07/16] chore: fix some typos for build-guide-*.md (#1958) Signed-off-by: hidewrong <hidewrong@outlook.com> --- build-guide-linux.md | 2 +- build-guide-win.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build-guide-linux.md b/build-guide-linux.md index 99c2ed0c8..df5f0f601 100644 --- a/build-guide-linux.md +++ b/build-guide-linux.md @@ -115,7 +115,7 @@ Install Flutter package dependencies with this command: > `$ ./cakewallet.sh` > and back to project root directory: > `$ cd ../..` -> and fetch dependecies again +> and fetch dependencies again > `$ flutter pub get` Your CakeWallet binary will be built with some specific keys for iterate with 3rd party services. You may generate these secret keys placeholders with the following command: diff --git a/build-guide-win.md b/build-guide-win.md index 6ace961af..8cfd02c4c 100644 --- a/build-guide-win.md +++ b/build-guide-win.md @@ -16,14 +16,14 @@ These steps will help you configure and execute a build of CakeWallet from its s ### 1. Installing Package Dependencies For build CakeWallet windows application from sources you will be needed to have: -> [Install Flutter]Follow installation guide (https://docs.flutter.dev/get-started/install/windows) and install do not miss to dev tools (install https://docs.flutter.dev/get-started/install/windows/desktop#development-tools) which are required for windows desktop development (need to install Git for Windows and Visual Studio 2022). Then install `Desktop development with C++` packages via GUI Visual Studio 2022, or Visual Studio Build Tools 2022 including: `C++ Build Tools core features`, `C++ 2022 Redistributable Update`, `C++ core desktop features`, `MVC v143 - VS 2022 C++ x64/x86 build tools`, `C++ CMake tools for Windwos`, `Testing tools core features - Build Tools`, `C++ AddressSanitizer`. +> [Install Flutter]Follow installation guide (https://docs.flutter.dev/get-started/install/windows) and install do not miss to dev tools (install https://docs.flutter.dev/get-started/install/windows/desktop#development-tools) which are required for windows desktop development (need to install Git for Windows and Visual Studio 2022). Then install `Desktop development with C++` packages via GUI Visual Studio 2022, or Visual Studio Build Tools 2022 including: `C++ Build Tools core features`, `C++ 2022 Redistributable Update`, `C++ core desktop features`, `MVC v143 - VS 2022 C++ x64/x86 build tools`, `C++ CMake tools for Windows`, `Testing tools core features - Build Tools`, `C++ AddressSanitizer`. > [Install WSL] for building monero dependencies need to install Windows WSL (https://learn.microsoft.com/en-us/windows/wsl/install) and required packages for WSL (Ubuntu): `$ sudo apt update ` `$ sudo apt build-essential cmake gcc-mingw-w64 g++-mingw-w64 autoconf libtool pkg-config` ### 2. Pull CakeWallet source code -You can downlaod CakeWallet source code from our [GitHub repository](github.com/cake-tech/cake_wallet) via git by following next command: +You can download CakeWallet source code from our [GitHub repository](github.com/cake-tech/cake_wallet) via git by following next command: `$ git clone https://github.com/cake-tech/cake_wallet.git --branch MrCyjaneK-cyjan-monerodart` OR you can download it as [Zip archive](https://github.com/cake-tech/cake_wallet/archive/refs/heads/MrCyjaneK-cyjan-monerodart.zip) From 3e10023e187ec098de80ee2c984401ef2ef664b4 Mon Sep 17 00:00:00 2001 From: cyan <cyjan@mrcyjanek.net> Date: Wed, 15 Jan 2025 12:09:59 +0100 Subject: [PATCH 08/16] CW-827 CI/CD update (#1948) * CI update - use existing build outputs in build_monero_all.sh - update $HOME, fix gh actions - add secrets earlier in the runtime (potentially speed up 'Build generated code' step) - add windows dockerfile - add linux/android dockerfile - update android/linux ci script * [skip slack] [run tests] Run tests on CI, fix tests * [skip slack] [run tests] force enable kvm in android * [skip slack] [run tests] remove inexisting flag * [run tests] [skip slack] update tests * add extra dependencies [skip ci] * [skip slack] [run tests] Add secrets * [skip slack] [run tests] Timeout test cases, continue on error * [skip slack] [run tests] Xvfb fix, timeout fix * [skip slack] [run tests] Start dbus to clean up the logs, use SIGKILL * [skip slack] [run tests] Enable network manager * [skip slack] [run tests] Screen record test, resize screen * [skip slack] [run tests] Improve status report for tests * [skip slack] [run tests] Increase framerate * [skip slack] [run tests] Remove test that I am unable to fix locally easily from CI * [skip slack] [run tests] Simplify ffmpeg command * [skip slack] [run tests] Increase timeout, add comment * [skip slack] Update dockerfile, migrate from mrcyjanek to cake-tech for the ghcr org * Update lib/entities/default_settings_migration.dart Co-authored-by: Omar Hatem <omarh.ismail1@gmail.com> --------- Co-authored-by: Omar Hatem <omarh.ismail1@gmail.com> --- .github/workflows/cache_dependencies.yml | 84 ---- .github/workflows/pr_test_build_android.yml | 412 +++++++++--------- .github/workflows/pr_test_build_linux.yml | 373 +++++++++------- cw_monero/lib/api/wallet.dart | 4 +- .../components/common_test_cases.dart | 5 + .../components/common_test_flows.dart | 34 +- integration_test/funds_related_tests.dart | 5 + integration_test/robots/auth_page_robot.dart | 5 + .../robots/pin_code_widget_robot.dart | 14 + .../restore_from_seed_or_key_robot.dart | 20 +- integration_test/robots/send_page_robot.dart | 35 +- .../robots/wallet_seed_page_robot.dart | 16 +- .../test_suites/confirm_seeds_flow_test.dart | 8 + .../test_suites/exchange_flow_test.dart | 4 + ...estore_wallet_through_seeds_flow_test.dart | 3 + integration_test_runner.sh | 5 + .../screens/new_wallet/new_wallet_page.dart | 2 + .../wallet_restore_from_keys_form.dart | 2 + .../wallet_restore_from_seed_form.dart | 2 + .../wallet_unlock/wallet_unlock_page.dart | 2 + linux/my_application.cc | 7 +- model_generator.sh | 34 +- scripts/android/.gitignore | 1 + scripts/android/build_monero_all.sh | 60 +-- scripts/android/build_mwebd.sh | 5 +- scripts/linux/Dockerfile.linux | 148 +++++++ scripts/linux/build_monero_all.sh | 18 +- scripts/prepare_moneroc.sh | 4 +- scripts/windows/.gitignore | 1 + scripts/windows/Dockerfile.windows | 68 +++ scripts/windows/ci_entrypoint.ps1 | 5 + scripts/windows/ci_register.ps1 | 30 ++ 32 files changed, 862 insertions(+), 554 deletions(-) delete mode 100644 .github/workflows/cache_dependencies.yml create mode 100644 scripts/android/.gitignore create mode 100644 scripts/linux/Dockerfile.linux create mode 100644 scripts/windows/.gitignore create mode 100644 scripts/windows/Dockerfile.windows create mode 100644 scripts/windows/ci_entrypoint.ps1 create mode 100644 scripts/windows/ci_register.ps1 diff --git a/.github/workflows/cache_dependencies.yml b/.github/workflows/cache_dependencies.yml deleted file mode 100644 index cb2afa396..000000000 --- a/.github/workflows/cache_dependencies.yml +++ /dev/null @@ -1,84 +0,0 @@ -name: Cache Dependencies - -on: - workflow_dispatch: - push: - branches: [ main ] - -jobs: - test: - - runs-on: ubuntu-20.04 - - steps: - - name: Free Disk Space (Ubuntu) - uses: insightsengineering/disk-space-reclaimer@v1 - with: - tools-cache: true - android: false - dotnet: true - haskell: true - large-packages: true - swap-storage: true - docker-images: true - - - uses: actions/checkout@v2 - - uses: actions/setup-java@v2 - with: - distribution: "temurin" - java-version: "17" - - name: Configure placeholder git details - run: | - git config --global user.email "CI@cakewallet.com" - git config --global user.name "Cake Github Actions" - - name: Flutter action - uses: subosito/flutter-action@v1 - with: - flutter-version: "3.24.4" - channel: stable - - - name: Install package dependencies - run: sudo apt-get install -y curl unzip automake build-essential file pkg-config git python libtool libtinfo5 cmake clang - - - name: Execute Build and Setup Commands - run: | - sudo mkdir -p /opt/android - sudo chown $USER /opt/android - cd /opt/android - -y curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh - cargo install cargo-ndk - git clone https://github.com/cake-tech/cake_wallet.git --branch main - cd cake_wallet/scripts/android/ - ./install_ndk.sh - source ./app_env.sh cakewallet - chmod +x pubspec_gen.sh - ./app_config.sh - - - name: Cache Externals - id: cache-externals - uses: actions/cache@v3 - with: - path: | - /opt/android/cake_wallet/cw_haven/android/.cxx - /opt/android/cake_wallet/scripts/monero_c/release - key: ${{ hashFiles('**/prepare_moneroc.sh' ,'**/build_monero_all.sh' ,'**/cache_dependencies.yml') }} - - - if: ${{ steps.cache-externals.outputs.cache-hit != 'true' }} - name: Generate Externals - run: | - cd /opt/android/cake_wallet/scripts/android/ - source ./app_env.sh cakewallet - ./build_monero_all.sh - - - name: Cache Keystore - id: cache-keystore - uses: actions/cache@v3 - with: - path: /opt/android/cake_wallet/android/app - key: keystore - - - if: ${{ steps.cache-keystore.outputs.cache-hit != 'true' }} - name: Generate KeyStore - run: | - cd /opt/android/cake_wallet/android/app - keytool -genkey -v -keystore key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias testKey -noprompt -dname "CN=CakeWallet, OU=CakeWallet, O=CakeWallet, L=Florida, S=America, C=USA" -storepass $STORE_PASS -keypass $KEY_PASS diff --git a/.github/workflows/pr_test_build_android.yml b/.github/workflows/pr_test_build_android.yml index cdd0e40b4..2a7eec5c9 100644 --- a/.github/workflows/pr_test_build_android.yml +++ b/.github/workflows/pr_test_build_android.yml @@ -1,169 +1,93 @@ -name: PR Test Build +name: Cake Wallet Android -on: - pull_request: - branches: [main] - workflow_dispatch: - inputs: - branch: - description: "Branch name to build" - required: true - default: "main" +on: [push] +defaults: + run: + shell: bash jobs: PR_test_build: - runs-on: ubuntu-20.04 + runs-on: linux-amd64 + container: + image: ghcr.io/cake-tech/cake_wallet:main-linux + env: + STORE_PASS: test@cake_wallet + KEY_PASS: test@cake_wallet + MONEROC_CACHE_DIR_ROOT: /opt/generic_cache + BRANCH_NAME: ${{ github.head_ref || github.ref_name }} + ANDROID_AVD_HOME: /root/.android/avd + volumes: + - /opt/cw_cache_android/root/.cache:/root/.cache + - /opt/cw_cache_android/root/.android/avd/:/root/.android/avd + - /opt/cw_cache_android/root/.ccache:/root/.ccache + - /opt/cw_cache_android/root/.pub-cache/:/root/.pub-cache + - /opt/cw_cache_android/root/.gradle/:/root/.gradle + - /opt/cw_cache_android/root/.android/:/root/.android + - /opt/cw_cache_android/root/go/pkg:/root/go/pkg + - /opt/cw_cache_android/opt/generic_cache:/opt/generic_cache + - /dev/kvm:/dev/kvm strategy: matrix: api-level: [29] - env: - STORE_PASS: test@cake_wallet - KEY_PASS: test@cake_wallet - PR_NUMBER: ${{ github.event.number }} steps: - - name: is pr - if: github.event_name == 'pull_request' - run: echo "BRANCH_NAME=${GITHUB_HEAD_REF}" >> $GITHUB_ENV - - - name: is not pr - if: github.event_name != 'pull_request' - run: echo "BRANCH_NAME=${{ github.event.inputs.branch }}" >> $GITHUB_ENV - - - name: Free Disk Space (Ubuntu) - uses: insightsengineering/disk-space-reclaimer@v1 - with: - tools-cache: true - android: false - dotnet: true - haskell: true - large-packages: true - swap-storage: true - docker-images: true - - - uses: actions/checkout@v2 - - uses: actions/setup-java@v2 - with: - distribution: "temurin" - java-version: "17" - - name: Configure placeholder git details + - name: Fix github actions messing up $HOME... + run: 'echo HOME=/root | sudo tee -a $GITHUB_ENV' + - uses: actions/checkout@v4 + - name: configure git run: | - git config --global user.email "CI@cakewallet.com" - git config --global user.name "Cake Github Actions" - - name: Flutter action - uses: subosito/flutter-action@v1 - with: - flutter-version: "3.24.0" - channel: stable - - - name: Install package dependencies - run: | - sudo apt update - sudo apt-get install -y curl unzip automake build-essential file pkg-config git python libtool libtinfo5 cmake clang - - - - name: Clone Repo - run: | - sudo mkdir -p /opt/android - sudo chown $USER /opt/android - cd /opt/android - git clone https://github.com/cake-tech/cake_wallet.git --branch ${{ env.BRANCH_NAME }} - -# - name: Cache Keystore -# id: cache-keystore -# uses: actions/cache@v3 -# with: -# path: /opt/android/cake_wallet/android/app -# key: keystore -# -# - if: ${{ steps.cache-keystore.outputs.cache-hit != 'true' }} - - name: Generate KeyStore - run: | - cd /opt/android/cake_wallet/android/app - keytool -genkey -v -keystore key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias testKey -noprompt -dname "CN=CakeWallet, OU=CakeWallet, O=CakeWallet, L=Florida, S=America, C=USA" -storepass $STORE_PASS -keypass $KEY_PASS - - - name: Execute Build and Setup Commands - run: | - cd /opt/android - -y curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh - cargo install cargo-ndk - cd cake_wallet/scripts/android/ - ./install_ndk.sh - source ./app_env.sh cakewallet - chmod +x pubspec_gen.sh - ./app_config.sh - - - name: Cache Externals - id: cache-externals - uses: actions/cache@v3 - with: - path: | - /opt/android/cake_wallet/cw_haven/android/.cxx - /opt/android/cake_wallet/scripts/monero_c/release - key: ${{ hashFiles('**/prepare_moneroc.sh' ,'**/build_monero_all.sh' ,'**/cache_dependencies.yml') }} - - - if: ${{ steps.cache-externals.outputs.cache-hit != 'true' }} - name: Generate Externals - run: | - cd /opt/android/cake_wallet/scripts/android/ - source ./app_env.sh cakewallet - ./build_monero_all.sh - - - name: Install Flutter dependencies - run: | - cd /opt/android/cake_wallet - flutter pub get - - - - name: Install go and gomobile - run: | - # install go > 1.23: - wget https://go.dev/dl/go1.23.1.linux-amd64.tar.gz - sudo rm -rf /usr/local/go && sudo tar -C /usr/local -xzf go1.23.1.linux-amd64.tar.gz - export PATH=$PATH:/usr/local/go/bin - export PATH=$PATH:~/go/bin - go install golang.org/x/mobile/cmd/gomobile@latest - gomobile init - - - name: Build mwebd - run: | - # paths are reset after each step, so we need to set them again: - export PATH=$PATH:/usr/local/go/bin - export PATH=$PATH:~/go/bin - cd /opt/android/cake_wallet/scripts/android/ - ./build_mwebd.sh --dont-install - - - name: Generate key properties - run: | - cd /opt/android/cake_wallet - dart run tool/generate_android_key_properties.dart keyAlias=testKey storeFile=key.jks storePassword=$STORE_PASS keyPassword=$KEY_PASS - - - name: Generate localization - run: | - cd /opt/android/cake_wallet - dart run tool/generate_localization.dart - - - name: Build generated code - run: | - cd /opt/android/cake_wallet - ./model_generator.sh - + git config --global user.email "ci@cakewallet.com" + git config --global user.name "CakeWallet CI" - name: Add secrets run: | - cd /opt/android/cake_wallet touch lib/.secrets.g.dart touch cw_evm/lib/.secrets.g.dart touch cw_solana/lib/.secrets.g.dart touch cw_core/lib/.secrets.g.dart touch cw_nano/lib/.secrets.g.dart touch cw_tron/lib/.secrets.g.dart - echo "const salt = '${{ secrets.SALT }}';" > lib/.secrets.g.dart - echo "const keychainSalt = '${{ secrets.KEY_CHAIN_SALT }}';" >> lib/.secrets.g.dart - echo "const key = '${{ secrets.KEY }}';" >> lib/.secrets.g.dart - echo "const walletSalt = '${{ secrets.WALLET_SALT }}';" >> lib/.secrets.g.dart - echo "const shortKey = '${{ secrets.SHORT_KEY }}';" >> lib/.secrets.g.dart - echo "const backupSalt = '${{ secrets.BACKUP_SALT }}';" >> lib/.secrets.g.dart - echo "const backupKeychainSalt = '${{ secrets.BACKUP_KEY_CHAIN_SALT }}';" >> lib/.secrets.g.dart + if [[ "x${{ secrets.SALT }}" == "x" ]]; + then + echo "const salt = '954f787f12622067f7e548d9450c3832';" > lib/.secrets.g.dart + else + echo "const salt = '${{ secrets.SALT }}';" > lib/.secrets.g.dart + fi + if [[ "x${{ secrets.KEY_CHAIN_SALT }}" == "x" ]]; + then + echo "const keychainSalt = '2d2beba777dbf7dff7013b7a';" >> lib/.secrets.g.dart + else + echo "const keychainSalt = '${{ secrets.KEY_CHAIN_SALT }}';" >> lib/.secrets.g.dart + fi + if [[ "x${{ secrets.KEY }}" == "x" ]]; + then + echo "const key = '638e98820ec10a2945e968435c9397a3';" >> lib/.secrets.g.dart + else + echo "const key = '${{ secrets.KEY }}';" >> lib/.secrets.g.dart + fi + if [[ "x${{ secrets.WALLET_SALT }}" == "x" ]]; + then + echo "const walletSalt = '8f7f1b70';" >> lib/.secrets.g.dart + else + echo "const walletSalt = '${{ secrets.WALLET_SALT }}';" >> lib/.secrets.g.dart + fi + if [[ "x${{ secrets.SHORT_KEY }}" == "x" ]]; + then + echo "const shortKey = '653f270c2c152bc7ec864afe';" >> lib/.secrets.g.dart + else + echo "const shortKey = '${{ secrets.SHORT_KEY }}';" >> lib/.secrets.g.dart + fi + if [[ "x${{ secrets.BACKUP_SALT }}" == "x" ]]; + then + echo "const backupSalt = 'bf630d24ff0b6f60';" >> lib/.secrets.g.dart + else + echo "const backupSalt = '${{ secrets.BACKUP_SALT }}';" >> lib/.secrets.g.dart + fi + if [[ "x${{ secrets.BACKUP_KEY_CHAIN_SALT }}" == "x" ]]; + then + echo "const backupKeychainSalt = 'bf630d24ff0b6f60';" >> lib/.secrets.g.dart + else + echo "const backupKeychainSalt = '${{ secrets.BACKUP_KEY_CHAIN_SALT }}';" >> lib/.secrets.g.dart + fi echo "const changeNowApiKey = '${{ secrets.CHANGE_NOW_API_KEY }}';" >> lib/.secrets.g.dart echo "const changeNowApiKeyDesktop = '${{ secrets.CHANGE_NOW_API_KEY_DESKTOP }}';" >> lib/.secrets.g.dart echo "const wyreSecretKey = '${{ secrets.WYRE_SECRET_KEY }}';" >> lib/.secrets.g.dart @@ -213,86 +137,152 @@ jobs: echo "const letsExchangeAffiliateId = '${{ secrets.LETS_EXCHANGE_AFFILIATE_ID }}';" >> lib/.secrets.g.dart echo "const stealthExBearerToken = '${{ secrets.STEALTH_EX_BEARER_TOKEN }}';" >> lib/.secrets.g.dart echo "const stealthExAdditionalFeePercent = '${{ secrets.STEALTH_EX_ADDITIONAL_FEE_PERCENT }}';" >> lib/.secrets.g.dart + # for tests + echo "const moneroTestWalletSeeds ='${{ secrets.MONERO_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart + echo "const moneroLegacyTestWalletSeeds = '${{ secrets.MONERO_LEGACY_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart + echo "const bitcoinTestWalletSeeds = '${{ secrets.BITCOIN_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart + echo "const ethereumTestWalletSeeds = '${{ secrets.ETHEREUM_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart + echo "const litecoinTestWalletSeeds = '${{ secrets.LITECOIN_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart + echo "const bitcoinCashTestWalletSeeds = '${{ secrets.BITCOIN_CASH_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart + echo "const polygonTestWalletSeeds = '${{ secrets.POLYGON_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart + echo "const solanaTestWalletSeeds = '${{ secrets.SOLANA_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart + echo "const tronTestWalletSeeds = '${{ secrets.TRON_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart + echo "const nanoTestWalletSeeds = '${{ secrets.NANO_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart + echo "const wowneroTestWalletSeeds = '${{ secrets.WOWNERO_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart + echo "const moneroTestWalletReceiveAddress = '${{ secrets.MONERO_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart + echo "const bitcoinTestWalletReceiveAddress = '${{ secrets.BITCOIN_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart + echo "const ethereumTestWalletReceiveAddress = '${{ secrets.ETHEREUM_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart + echo "const litecoinTestWalletReceiveAddress = '${{ secrets.LITECOIN_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart + echo "const bitcoinCashTestWalletReceiveAddress = '${{ secrets.BITCOIN_CASH_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart + echo "const polygonTestWalletReceiveAddress = '${{ secrets.POLYGON_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart + echo "const solanaTestWalletReceiveAddress = '${{ secrets.SOLANA_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart + echo "const tronTestWalletReceiveAddress = '${{ secrets.TRON_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart + echo "const nanoTestWalletReceiveAddress = '${{ secrets.NANO_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart + echo "const wowneroTestWalletReceiveAddress = '${{ secrets.WOWNERO_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart + echo "const moneroTestWalletBlockHeight = '${{ secrets.MONERO_TEST_WALLET_BLOCK_HEIGHT }}';" >> lib/.secrets.g.dart + - name: prepare monero_c and cache + run: | + export MONEROC_HASH=$(cat scripts/prepare_moneroc.sh | grep 'git checkout' | xargs | awk '{ print $3 }') + echo MONEROC_HASH=$MONEROC_HASH >> /etc/environment + mkdir -p "$MONEROC_CACHE_DIR_ROOT/moneroc-$MONEROC_HASH/monero_c" + pushd scripts + ln -s "$MONEROC_CACHE_DIR_ROOT/moneroc-$MONEROC_HASH/monero_c" + ./prepare_moneroc.sh + popd + pushd scripts/monero_c + mkdir -p "$MONEROC_CACHE_DIR_ROOT/_cache/contrib/depends/built" || true + mkdir -p "$MONEROC_CACHE_DIR_ROOT/_cache/monero/contrib/depends/built" || true + mkdir -p "$MONEROC_CACHE_DIR_ROOT/_cache/wownero/contrib/depends/built" || true + mkdir -p "$MONEROC_CACHE_DIR_ROOT/_cache/contrib/depends/sources" || true + mkdir -p "$MONEROC_CACHE_DIR_ROOT/_cache/monero/contrib/depends/sources" || true + mkdir -p "$MONEROC_CACHE_DIR_ROOT/_cache/wownero/contrib/depends/sources" || true + + rm -rf "$PWD/contrib/depends/built" "$PWD/monero/contrib/depends/built" "$PWD/wownero/contrib/depends/built" + rm -rf "$PWD/contrib/depends/sources" "$PWD/monero/contrib/depends/sources" "$PWD/wownero/contrib/depends/sources" + mkdir -p contrib/depends || true + ln -sf "$MONEROC_CACHE_DIR_ROOT/_cache/contrib/depends/built" "$PWD/contrib/depends/built" + ln -sf "$MONEROC_CACHE_DIR_ROOT/_cache/monero/contrib/depends/built" "$PWD/monero/contrib/depends/built" + ln -sf "$MONEROC_CACHE_DIR_ROOT/_cache/wownero/contrib/depends/built" "$PWD/wownero/contrib/depends/built" + ln -sf "$MONEROC_CACHE_DIR_ROOT/_cache/contrib/depends/sources" "$PWD/contrib/depends/sources" + ln -sf "$MONEROC_CACHE_DIR_ROOT/_cache/monero/contrib/depends/sources" "$PWD/monero/contrib/depends/sources" + ln -sf "$MONEROC_CACHE_DIR_ROOT/_cache/wownero/contrib/depends/sources" "$PWD/wownero/contrib/depends/sources" + popd + + - name: Generate KeyStore + run: | + pushd /opt/generic_cache + if [[ ! -f key.jks ]]; + then + keytool -genkey -v -keystore key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias testKey -noprompt -dname "CN=CakeWallet, OU=CakeWallet, O=CakeWallet, L=Florida, S=America, C=USA" -storepass $STORE_PASS -keypass $KEY_PASS + else + echo "$PWD/key.jks exist, not generating" + fi + popd + cp /opt/generic_cache/key.jks android/app + + - name: Execute Build and Setup Commands + run: | + pushd scripts/android + source ./app_env.sh cakewallet + ./app_config.sh + popd + + - name: Build monero_c + run: | + pushd scripts/android/ + source ./app_env.sh cakewallet + ./build_monero_all.sh + popd + + - name: Install Flutter dependencies + run: | + flutter pub get + + - name: Build mwebd + run: | + set -x -e + export MWEBD_HASH=$(cat scripts/android/build_mwebd.sh | grep 'git reset --hard' | xargs | awk '{ print $4 }') + echo MWEBD_HASH=$MWEBD_HASH >> /etc/environment + pushd scripts/android + gomobile init; + ./build_mwebd.sh --dont-install + popd + + - name: Build generated code + run: | + ./model_generator.sh async + + - name: Generate key properties + run: | + dart run tool/generate_android_key_properties.dart keyAlias=testKey storeFile=key.jks storePassword=$STORE_PASS keyPassword=$KEY_PASS + + - name: Generate localization + run: | + dart run tool/generate_localization.dart - name: Rename app run: | - echo -e "id=com.cakewallet.test_${{ env.PR_NUMBER }}\nname=${{ env.BRANCH_NAME }}" > /opt/android/cake_wallet/android/app.properties + sanitized_branch_name=${BRANCH_NAME#origin/} # Remove 'origin/' prefix if it exists + sanitized_branch_name=${sanitized_branch_name:0:16} # Take only the first 16 characters + sanitized_branch_name=$(echo "$sanitized_branch_name" | tr '[:upper:]' '[:lower:]') # Convert to lowercase + sanitized_branch_name=$(echo "$sanitized_branch_name" | sed 's/[^a-z0-9]//g') # Remove all special characters - # Step 3: Download previous build number - - name: Download previous build number - id: download-build-number - run: | - # Download the artifact if it exists - if [[ ! -f build_number.txt ]]; then - echo "1" > build_number.txt - fi - - # Step 4: Read and Increment Build Number - - name: Increment Build Number - id: increment-build-number - run: | - # Read current build number from file - BUILD_NUMBER=$(cat build_number.txt) - BUILD_NUMBER=$((BUILD_NUMBER + 1)) - echo "New build number: $BUILD_NUMBER" - - # Save the incremented build number - echo "$BUILD_NUMBER" > build_number.txt - - # Export the build number to use in later steps - echo "BUILD_NUMBER=$BUILD_NUMBER" >> $GITHUB_ENV - - # Step 5: Update pubspec.yaml with new build number - - name: Update build number - run: | - cd /opt/android/cake_wallet - sed -i "s/^version: .*/version: 1.0.$BUILD_NUMBER/" pubspec.yaml + echo -e "id=com.cakewallet.test_${sanitized_branch_name}\nname=${BRANCH_NAME}" > android/app.properties - name: Build run: | - cd /opt/android/cake_wallet flutter build apk --release --split-per-abi - # - name: Push to App Center - # run: | - # echo 'Installing App Center CLI tools' - # npm install -g appcenter-cli - # echo "Publishing test to App Center" - # appcenter distribute release \ - # --group "Testers" \ - # --file "/opt/android/cake_wallet/build/app/outputs/apk/release/app-release.apk" \ - # --release-notes ${{ env.BRANCH_NAME }} \ - # --app Cake-Labs/Cake-Wallet \ - # --token ${{ secrets.APP_CENTER_TOKEN }} \ - # --quiet - - name: Rename apk file run: | - cd /opt/android/cake_wallet/build/app/outputs/flutter-apk + cd build/app/outputs/flutter-apk mkdir test-apk - cp app-arm64-v8a-release.apk test-apk/${{env.BRANCH_NAME}}.apk - cp app-x86_64-release.apk test-apk/${{env.BRANCH_NAME}}_x86.apk + cp app-arm64-v8a-release.apk test-apk/${BRANCH_NAME}.apk + cp app-x86_64-release.apk test-apk/${BRANCH_NAME}_x86.apk + cd test-apk + cp ${BRANCH_NAME}.apk ${BRANCH_NAME}_slack.apk - - name: Upload Artifact - uses: kittaakos/upload-artifact-as-is@v0 - with: - path: /opt/android/cake_wallet/build/app/outputs/flutter-apk/test-apk/ - - # Re-upload updated build number for the next run - - name: Upload updated build number - uses: actions/upload-artifact@v3 - with: - name: build_number - path: build_number.txt - - - name: Send Test APK + - name: Find APK file + id: find_apk + run: | + set -x + apk_file=$(ls build/app/outputs/flutter-apk/test-apk/*_slack.apk || exit 1) + echo "APK_FILE=$apk_file" >> $GITHUB_ENV + + - name: Upload artifact to slack + if: ${{ !contains(github.event.head_commit.message, 'skip slack') }} continue-on-error: true uses: adrey/slack-file-upload-action@1.0.5 with: token: ${{ secrets.SLACK_APP_TOKEN }} - path: /opt/android/cake_wallet/build/app/outputs/flutter-apk/test-apk/${{env.BRANCH_NAME}}.apk + path: ${{ env.APK_FILE }} channel: ${{ secrets.SLACK_APK_CHANNEL }} - title: "${{ env.BRANCH_NAME }}.apk" - filename: ${{ env.BRANCH_NAME }}.apk initial_comment: ${{ github.event.head_commit.message }} + - name: cleanup + run: rm -rf build/app/outputs/flutter-apk/test-apk/ + + - name: Upload Artifact to github + uses: kittaakos/upload-artifact-as-is@v0 + with: + path: ${{ github.workspace }}/build/app/outputs/flutter-apk \ No newline at end of file diff --git a/.github/workflows/pr_test_build_linux.yml b/.github/workflows/pr_test_build_linux.yml index 891327d1e..6a29e4033 100644 --- a/.github/workflows/pr_test_build_linux.yml +++ b/.github/workflows/pr_test_build_linux.yml @@ -1,139 +1,89 @@ -name: PR Test Build linux +name: Cake Wallet Linux -on: - pull_request: - branches: [main] - workflow_dispatch: - inputs: - branch: - description: "Branch name to build" - required: true - default: "main" +on: [push] +defaults: + run: + shell: bash jobs: PR_test_build: - runs-on: ubuntu-20.04 - env: - STORE_PASS: test@cake_wallet - KEY_PASS: test@cake_wallet - PR_NUMBER: ${{ github.event.number }} + runs-on: linux-amd64 + container: + image: ghcr.io/cake-tech/cake_wallet:main-linux + env: + STORE_PASS: test@cake_wallet + KEY_PASS: test@cake_wallet + MONEROC_CACHE_DIR_ROOT: /opt/generic_cache + BRANCH_NAME: ${{ github.head_ref || github.ref_name }} + DESKTOP_FORCE_MOBILE: Y + volumes: + - /opt/cw_cache_linux/root/.cache:/root/.cache + - /opt/cw_cache_linux/root/.ccache:/root/.ccache + - /opt/cw_cache_linux/root/.pub-cache/:/root/.pub-cache + - /opt/cw_cache_linux/root/go/pkg:/root/go/pkg + - /opt/cw_cache_linux/opt/generic_cache:/opt/generic_cache + strategy: + matrix: + api-level: [29] steps: - - name: is pr - if: github.event_name == 'pull_request' - run: echo "BRANCH_NAME=${GITHUB_HEAD_REF}" >> $GITHUB_ENV - - - name: is not pr - if: github.event_name != 'pull_request' - run: echo "BRANCH_NAME=${{ github.event.inputs.branch }}" >> $GITHUB_ENVg - - - uses: actions/checkout@v2 - - uses: actions/setup-java@v1 - with: - java-version: "17.x" - - name: Configure placeholder git details + - name: Fix github actions messing up $HOME... + run: 'echo HOME=/root | sudo tee -a $GITHUB_ENV' + - uses: actions/checkout@v4 + - name: configure git run: | - git config --global user.email "CI@cakewallet.com" - git config --global user.name "Cake Github Actions" - - name: Flutter action - uses: subosito/flutter-action@v1 - with: - flutter-version: "3.24.0" - channel: stable - - - name: Install package dependencies - run: | - sudo apt update - sudo apt-get install -y curl unzip automake build-essential file pkg-config git python-is-python3 libtool libtinfo5 cmake clang - - - name: Install desktop dependencies - run: | - sudo apt update - sudo apt install -y ninja-build libgtk-3-dev gperf - - name: Execute Build and Setup Commands - run: | - sudo mkdir -p /opt/android - sudo chown $USER /opt/android - cd /opt/android - -y curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh - cargo install cargo-ndk - git clone https://github.com/cake-tech/cake_wallet.git --branch ${{ env.BRANCH_NAME }} - cd scripts && ./gen_android_manifest.sh && cd .. - cd cake_wallet/scripts/android/ - source ./app_env.sh cakewallet - ./app_config.sh - cd ../../.. - cd cake_wallet/scripts/linux/ - source ./app_env.sh cakewallet - ./app_config.sh - cd ../../.. - - - name: Cache Externals - id: cache-externals - uses: actions/cache@v3 - with: - path: | - /opt/android/cake_wallet/cw_haven/android/.cxx - /opt/android/cake_wallet/scripts/monero_c/release - key: linux_${{ hashFiles('**/prepare_moneroc.sh' ,'**/build_monero_all.sh' ,'**/cache_dependencies.yml') }} - - - if: ${{ steps.cache-externals.outputs.cache-hit != 'true' }} - name: Generate Externals - run: | - cd /opt/android/cake_wallet/scripts/linux/ - source ./app_env.sh cakewallet - ./build_monero_all.sh - - - name: Install Flutter dependencies - run: | - cd /opt/android/cake_wallet - flutter pub get - - - name: Install go and gomobile - run: | - # install go > 1.23: - wget https://go.dev/dl/go1.23.1.linux-amd64.tar.gz - sudo rm -rf /usr/local/go && sudo tar -C /usr/local -xzf go1.23.1.linux-amd64.tar.gz - export PATH=$PATH:/usr/local/go/bin - export PATH=$PATH:~/go/bin - go install golang.org/x/mobile/cmd/gomobile@latest - gomobile init - - - name: Build mwebd - run: | - # paths are reset after each step, so we need to set them again: - export PATH=$PATH:/usr/local/go/bin - export PATH=$PATH:~/go/bin - # build mwebd: - cd /opt/android/cake_wallet/scripts/android/ - ./build_mwebd.sh --dont-install - - - name: Generate localization - run: | - cd /opt/android/cake_wallet - dart run tool/generate_localization.dart - - - name: Build generated code - run: | - cd /opt/android/cake_wallet - ./model_generator.sh - + git config --global user.email "ci@cakewallet.com" + git config --global user.name "CakeWallet CI" - name: Add secrets run: | - cd /opt/android/cake_wallet touch lib/.secrets.g.dart touch cw_evm/lib/.secrets.g.dart touch cw_solana/lib/.secrets.g.dart touch cw_core/lib/.secrets.g.dart touch cw_nano/lib/.secrets.g.dart touch cw_tron/lib/.secrets.g.dart - echo "const salt = '${{ secrets.SALT }}';" > lib/.secrets.g.dart - echo "const keychainSalt = '${{ secrets.KEY_CHAIN_SALT }}';" >> lib/.secrets.g.dart - echo "const key = '${{ secrets.KEY }}';" >> lib/.secrets.g.dart - echo "const walletSalt = '${{ secrets.WALLET_SALT }}';" >> lib/.secrets.g.dart - echo "const shortKey = '${{ secrets.SHORT_KEY }}';" >> lib/.secrets.g.dart - echo "const backupSalt = '${{ secrets.BACKUP_SALT }}';" >> lib/.secrets.g.dart - echo "const backupKeychainSalt = '${{ secrets.BACKUP_KEY_CHAIN_SALT }}';" >> lib/.secrets.g.dart + if [[ "x${{ secrets.SALT }}" == "x" ]]; + then + echo "const salt = '954f787f12622067f7e548d9450c3832';" > lib/.secrets.g.dart + else + echo "const salt = '${{ secrets.SALT }}';" > lib/.secrets.g.dart + fi + if [[ "x${{ secrets.KEY_CHAIN_SALT }}" == "x" ]]; + then + echo "const keychainSalt = '2d2beba777dbf7dff7013b7a';" >> lib/.secrets.g.dart + else + echo "const keychainSalt = '${{ secrets.KEY_CHAIN_SALT }}';" >> lib/.secrets.g.dart + fi + if [[ "x${{ secrets.KEY }}" == "x" ]]; + then + echo "const key = '638e98820ec10a2945e968435c9397a3';" >> lib/.secrets.g.dart + else + echo "const key = '${{ secrets.KEY }}';" >> lib/.secrets.g.dart + fi + if [[ "x${{ secrets.WALLET_SALT }}" == "x" ]]; + then + echo "const walletSalt = '8f7f1b70';" >> lib/.secrets.g.dart + else + echo "const walletSalt = '${{ secrets.WALLET_SALT }}';" >> lib/.secrets.g.dart + fi + if [[ "x${{ secrets.SHORT_KEY }}" == "x" ]]; + then + echo "const shortKey = '653f270c2c152bc7ec864afe';" >> lib/.secrets.g.dart + else + echo "const shortKey = '${{ secrets.SHORT_KEY }}';" >> lib/.secrets.g.dart + fi + if [[ "x${{ secrets.BACKUP_SALT }}" == "x" ]]; + then + echo "const backupSalt = 'bf630d24ff0b6f60';" >> lib/.secrets.g.dart + else + echo "const backupSalt = '${{ secrets.BACKUP_SALT }}';" >> lib/.secrets.g.dart + fi + if [[ "x${{ secrets.BACKUP_KEY_CHAIN_SALT }}" == "x" ]]; + then + echo "const backupKeychainSalt = 'bf630d24ff0b6f60';" >> lib/.secrets.g.dart + else + echo "const backupKeychainSalt = '${{ secrets.BACKUP_KEY_CHAIN_SALT }}';" >> lib/.secrets.g.dart + fi echo "const changeNowApiKey = '${{ secrets.CHANGE_NOW_API_KEY }}';" >> lib/.secrets.g.dart echo "const changeNowApiKeyDesktop = '${{ secrets.CHANGE_NOW_API_KEY_DESKTOP }}';" >> lib/.secrets.g.dart echo "const wyreSecretKey = '${{ secrets.WYRE_SECRET_KEY }}';" >> lib/.secrets.g.dart @@ -144,8 +94,6 @@ jobs: echo "const sideShiftAffiliateId = '${{ secrets.SIDE_SHIFT_AFFILIATE_ID }}';" >> lib/.secrets.g.dart echo "const simpleSwapApiKey = '${{ secrets.SIMPLE_SWAP_API_KEY }}';" >> lib/.secrets.g.dart echo "const simpleSwapApiKeyDesktop = '${{ secrets.SIMPLE_SWAP_API_KEY_DESKTOP }}';" >> lib/.secrets.g.dart - echo "const polygonScanApiKey = '${{ secrets.POLYGON_SCAN_API_KEY }}';" >> lib/.secrets.g.dart - echo "const etherScanApiKey = '${{ secrets.ETHER_SCAN_API_KEY }}';" >> lib/.secrets.g.dart echo "const onramperApiKey = '${{ secrets.ONRAMPER_API_KEY }}';" >> lib/.secrets.g.dart echo "const anypayToken = '${{ secrets.ANY_PAY_TOKEN }}';" >> lib/.secrets.g.dart echo "const ioniaClientId = '${{ secrets.IONIA_CLIENT_ID }}';" >> lib/.secrets.g.dart @@ -156,8 +104,11 @@ jobs: echo "const fiatApiKey = '${{ secrets.FIAT_API_KEY }}';" >> lib/.secrets.g.dart echo "const ankrApiKey = '${{ secrets.ANKR_API_KEY }}';" >> lib/.secrets.g.dart echo "const chainStackApiKey = '${{ secrets.CHAIN_STACK_API_KEY }}';" >> lib/.secrets.g.dart + echo "const etherScanApiKey = '${{ secrets.ETHER_SCAN_API_KEY }}';" >> lib/.secrets.g.dart + echo "const polygonScanApiKey = '${{ secrets.POLYGON_SCAN_API_KEY }}';" >> 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 nowNodesApiKey = '${{ secrets.EVM_NOWNODES_API_KEY }}';" >> cw_evm/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 robinhoodApplicationId = '${{ secrets.ROBINHOOD_APPLICATION_ID }}';" >> lib/.secrets.g.dart @@ -165,7 +116,6 @@ jobs: echo "const walletConnectProjectId = '${{ secrets.WALLET_CONNECT_PROJECT_ID }}';" >> lib/.secrets.g.dart echo "const moralisApiKey = '${{ secrets.MORALIS_API_KEY }}';" >> lib/.secrets.g.dart echo "const polygonScanApiKey = '${{ secrets.POLYGON_SCAN_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart - echo "const nowNodesApiKey = '${{ secrets.EVM_NOWNODES_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart echo "const ankrApiKey = '${{ secrets.ANKR_API_KEY }}';" >> cw_solana/lib/.secrets.g.dart echo "const chainStackApiKey = '${{ secrets.CHAIN_STACK_API_KEY }}';" >> cw_solana/lib/.secrets.g.dart echo "const testCakePayApiKey = '${{ secrets.TEST_CAKE_PAY_API_KEY }}';" >> lib/.secrets.g.dart @@ -178,39 +128,170 @@ jobs: echo "const tronGridApiKey = '${{ secrets.TRON_GRID_API_KEY }}';" >> cw_tron/lib/.secrets.g.dart echo "const tronNowNodesApiKey = '${{ secrets.TRON_NOW_NODES_API_KEY }}';" >> cw_tron/lib/.secrets.g.dart echo "const meldTestApiKey = '${{ secrets.MELD_TEST_API_KEY }}';" >> lib/.secrets.g.dart - echo "const meldTestPublicKey = '${{ secrets.MELD_TEST_PUBLIC_KEY}}';" >> lib/.secrets.g.dar + echo "const meldTestPublicKey = '${{ secrets.MELD_TEST_PUBLIC_KEY}}';" >> lib/.secrets.g.dart echo "const letsExchangeBearerToken = '${{ secrets.LETS_EXCHANGE_TOKEN }}';" >> lib/.secrets.g.dart echo "const letsExchangeAffiliateId = '${{ secrets.LETS_EXCHANGE_AFFILIATE_ID }}';" >> lib/.secrets.g.dart echo "const stealthExBearerToken = '${{ secrets.STEALTH_EX_BEARER_TOKEN }}';" >> lib/.secrets.g.dart echo "const stealthExAdditionalFeePercent = '${{ secrets.STEALTH_EX_ADDITIONAL_FEE_PERCENT }}';" >> lib/.secrets.g.dart - - - name: Rename app + # tests + echo "const moneroTestWalletSeeds ='${{ secrets.MONERO_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart + echo "const moneroLegacyTestWalletSeeds = '${{ secrets.MONERO_LEGACY_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart + echo "const bitcoinTestWalletSeeds = '${{ secrets.BITCOIN_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart + echo "const ethereumTestWalletSeeds = '${{ secrets.ETHEREUM_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart + echo "const litecoinTestWalletSeeds = '${{ secrets.LITECOIN_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart + echo "const bitcoinCashTestWalletSeeds = '${{ secrets.BITCOIN_CASH_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart + echo "const polygonTestWalletSeeds = '${{ secrets.POLYGON_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart + echo "const solanaTestWalletSeeds = '${{ secrets.SOLANA_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart + echo "const tronTestWalletSeeds = '${{ secrets.TRON_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart + echo "const nanoTestWalletSeeds = '${{ secrets.NANO_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart + echo "const wowneroTestWalletSeeds = '${{ secrets.WOWNERO_TEST_WALLET_SEEDS }}';" >> lib/.secrets.g.dart + echo "const moneroTestWalletReceiveAddress = '${{ secrets.MONERO_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart + echo "const bitcoinTestWalletReceiveAddress = '${{ secrets.BITCOIN_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart + echo "const ethereumTestWalletReceiveAddress = '${{ secrets.ETHEREUM_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart + echo "const litecoinTestWalletReceiveAddress = '${{ secrets.LITECOIN_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart + echo "const bitcoinCashTestWalletReceiveAddress = '${{ secrets.BITCOIN_CASH_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart + echo "const polygonTestWalletReceiveAddress = '${{ secrets.POLYGON_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart + echo "const solanaTestWalletReceiveAddress = '${{ secrets.SOLANA_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart + echo "const tronTestWalletReceiveAddress = '${{ secrets.TRON_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart + echo "const nanoTestWalletReceiveAddress = '${{ secrets.NANO_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart + echo "const wowneroTestWalletReceiveAddress = '${{ secrets.WOWNERO_TEST_WALLET_RECEIVE_ADDRESS }}';" >> lib/.secrets.g.dart + echo "const moneroTestWalletBlockHeight = '${{ secrets.MONERO_TEST_WALLET_BLOCK_HEIGHT }}';" >> lib/.secrets.g.dart + - name: prepare monero_c and cache run: | - echo -e "id=com.cakewallet.test_${{ env.PR_NUMBER }}\nname=${{ env.BRANCH_NAME }}" > /opt/android/cake_wallet/android/app.properties + export MONEROC_HASH=$(cat scripts/prepare_moneroc.sh | grep 'git checkout' | xargs | awk '{ print $3 }') + echo MONEROC_HASH=$MONEROC_HASH >> /etc/environment + mkdir -p "$MONEROC_CACHE_DIR_ROOT/moneroc-$MONEROC_HASH/monero_c" + pushd scripts + ln -s "$MONEROC_CACHE_DIR_ROOT/moneroc-$MONEROC_HASH/monero_c" + ./prepare_moneroc.sh + popd + pushd scripts/monero_c + mkdir -p "$MONEROC_CACHE_DIR_ROOT/_cache/contrib/depends/built" || true + mkdir -p "$MONEROC_CACHE_DIR_ROOT/_cache/monero/contrib/depends/built" || true + mkdir -p "$MONEROC_CACHE_DIR_ROOT/_cache/wownero/contrib/depends/built" || true + mkdir -p "$MONEROC_CACHE_DIR_ROOT/_cache/contrib/depends/sources" || true + mkdir -p "$MONEROC_CACHE_DIR_ROOT/_cache/monero/contrib/depends/sources" || true + mkdir -p "$MONEROC_CACHE_DIR_ROOT/_cache/wownero/contrib/depends/sources" || true - - name: Build + rm -rf "$PWD/contrib/depends/built" "$PWD/monero/contrib/depends/built" "$PWD/wownero/contrib/depends/built" + rm -rf "$PWD/contrib/depends/sources" "$PWD/monero/contrib/depends/sources" "$PWD/wownero/contrib/depends/sources" + mkdir -p contrib/depends || true + ln -sf "$MONEROC_CACHE_DIR_ROOT/_cache/contrib/depends/built" "$PWD/contrib/depends/built" + ln -sf "$MONEROC_CACHE_DIR_ROOT/_cache/monero/contrib/depends/built" "$PWD/monero/contrib/depends/built" + ln -sf "$MONEROC_CACHE_DIR_ROOT/_cache/wownero/contrib/depends/built" "$PWD/wownero/contrib/depends/built" + ln -sf "$MONEROC_CACHE_DIR_ROOT/_cache/contrib/depends/sources" "$PWD/contrib/depends/sources" + ln -sf "$MONEROC_CACHE_DIR_ROOT/_cache/monero/contrib/depends/sources" "$PWD/monero/contrib/depends/sources" + ln -sf "$MONEROC_CACHE_DIR_ROOT/_cache/wownero/contrib/depends/sources" "$PWD/wownero/contrib/depends/sources" + popd + + - name: Execute Build and Setup Commands + run: | + pushd scripts/linux + source ./app_env.sh cakewallet + ./app_config.sh + popd + + - name: Build monero_c + run: | + pushd scripts/linux/ + source ./app_env.sh cakewallet + ./build_monero_all.sh + popd + + - name: Install Flutter dependencies + run: | + flutter pub get + + - name: Build generated code + run: | + ./model_generator.sh async + + - name: Generate localization + run: | + dart run tool/generate_localization.dart + + - name: Build linux run: | - cd /opt/android/cake_wallet flutter build linux --release - - name: Prepare release zip file + - name: Compress release run: | - cd /opt/android/cake_wallet/build/linux/x64/release - zip -r ${{env.BRANCH_NAME}}.zip bundle + pushd build/linux/x64/release + zip -r cakewallet_linux.zip bundle + popd - - name: Upload Artifact + - name: Upload Artifact to github uses: kittaakos/upload-artifact-as-is@v0 with: - path: /opt/android/cake_wallet/build/linux/x64/release/${{env.BRANCH_NAME}}.zip + path: ${{ github.workspace }}/build/linux/x64/release/cakewallet_linux.zip -# Just as an artifact would be enough -# - name: Send Test APK -# continue-on-error: true -# uses: adrey/slack-file-upload-action@1.0.5 -# with: -# token: ${{ secrets.SLACK_APP_TOKEN }} -# path: /opt/android/cake_wallet/build/linux/x64/release/${{env.BRANCH_NAME}}.zip -# channel: ${{ secrets.SLACK_APK_CHANNEL }} -# title: "${{ env.BRANCH_NAME }}_linux.zip" -# filename: ${{ env.BRANCH_NAME }}_linux.zip -# initial_comment: ${{ github.event.head_commit.message }} + - name: Prepare virtual desktop + if: ${{ contains(github.event.head_commit.message, 'run tests') }} + run: | + nohup Xvfb :99 -screen 0 720x1280x16 & + echo DISPLAY=:99 | sudo tee -a $GITHUB_ENV + dbus-daemon --system --fork + nohup NetworkManager & + nohup ffmpeg -framerate 60 -video_size 720x1280 -f x11grab -i :99 -c:v libx264 -c:a aac /opt/screen_grab.mkv & + + # Note for people adding tests: + # - Tests are ran on Linux, with some things being mocked out. + # - Screen recording is being provided for the entire length of the test, you can download it in github articats. + # - Screen recordeding is encrypted, look at step "Stop screen recording, encrypt and upload", and add your key if you want + # Reason for encryption is the fact that we restore the wallet from seed, and we don't want to leak that, while there + # isn't much in those wallets anyway, we still wouldn't like to leak it to anyone who is able to access github. + + - name: Test [confirm_seeds_flow_test] + if: ${{ contains(github.event.head_commit.message, 'run tests') }} + timeout-minutes: 20 + run: | + xmessage -timeout 30 "confirm_seeds_flow_test" & + rm -rf ~/.local/share/com.example.cake_wallet/ ~/Documents/cake_wallet/ ~/cake_wallet + exec timeout --signal=SIGKILL 900 flutter drive --driver=test_driver/integration_test.dart --target=integration_test/test_suites/confirm_seeds_flow_test.dart + - name: Test [create_wallet_flow_test] + if: ${{ contains(github.event.head_commit.message, 'run tests') }} + timeout-minutes: 20 + run: | + xmessage -timeout 30 "create_wallet_flow_test" & + rm -rf ~/.local/share/com.example.cake_wallet/ ~/Documents/cake_wallet/ ~/cake_wallet + exec timeout --signal=SIGKILL 900 flutter drive --driver=test_driver/integration_test.dart --target=integration_test/test_suites/create_wallet_flow_test.dart + - name: Test [exchange_flow_test] + if: ${{ contains(github.event.head_commit.message, 'run tests') }} + timeout-minutes: 20 + run: | + xmessage -timeout 30 "exchange_flow_test" & + rm -rf ~/.local/share/com.example.cake_wallet/ ~/Documents/cake_wallet/ ~/cake_wallet + exec timeout --signal=SIGKILL 900 flutter drive --driver=test_driver/integration_test.dart --target=integration_test/test_suites/exchange_flow_test.dart + - name: Test [restore_wallet_through_seeds_flow_test] + if: ${{ contains(github.event.head_commit.message, 'run tests') }} + timeout-minutes: 20 + run: | + xmessage -timeout 30 "restore_wallet_through_seeds_flow_test" & + rm -rf ~/.local/share/com.example.cake_wallet/ ~/Documents/cake_wallet/ ~/cake_wallet + exec timeout --signal=SIGKILL 900 flutter drive --driver=test_driver/integration_test.dart --target=integration_test/test_suites/restore_wallet_through_seeds_flow_test.dart + - name: Stop screen recording, encrypt and upload + if: always() + run: | + if [[ ! -f "/opt/screen_grab.mkv" ]]; + then + exit 0; + fi + killall ffmpeg + sleep 5 + killall -9 ffmpeg || true + sleep 5 + # Feel free to add your own public key if you wish + gpg --keyserver hkps://keyserver.ubuntu.com --recv-keys 6B3199AD9B3D23B8 # konstantin@cakewallet.com + gpg --keyserver hkps://keyserver.ubuntu.com --recv-keys 35C8DBAFB8D9ACAC # cyjan@mrcyjanek.net + gpg --trust-model always --encrypt --output /opt/screen_grab.mkv.gpg \ + --recipient 6B3199AD9B3D23B8 \ + --recipient 35C8DBAFB8D9ACAC \ + /opt/screen_grab.mkv + rm /opt/screen_grab.mkv + mv /opt/screen_grab.mkv.gpg ./screen_grab.mkv.gpg + - name: Upload Artifact to github + if: always() + continue-on-error: true + uses: kittaakos/upload-artifact-as-is@v0 + with: + path: ${{ github.workspace }}/screen_grab.mkv.gpg diff --git a/cw_monero/lib/api/wallet.dart b/cw_monero/lib/api/wallet.dart index 537c9802e..2a343d430 100644 --- a/cw_monero/lib/api/wallet.dart +++ b/cw_monero/lib/api/wallet.dart @@ -9,6 +9,8 @@ import 'package:flutter/foundation.dart'; import 'package:monero/monero.dart' as monero; import 'package:mutex/mutex.dart'; +bool debugMonero = false; + int getSyncingHeight() { // final height = monero.MONERO_cw_WalletListener_height(getWlptr()); final h2 = monero.Wallet_blockChainHeight(wptr!); @@ -132,7 +134,7 @@ Future<bool> setupNodeSync( } } - if (kDebugMode) { + if (kDebugMode && debugMonero) { monero.Wallet_init3( wptr!, argv0: '', defaultLogBaseName: 'moneroc', diff --git a/integration_test/components/common_test_cases.dart b/integration_test/components/common_test_cases.dart index 83bbb0449..cc1e6d6d7 100644 --- a/integration_test/components/common_test_cases.dart +++ b/integration_test/components/common_test_cases.dart @@ -32,6 +32,11 @@ class CommonTestCases { expect(textWidget, hasWidget ? findsOneWidget : findsNothing); } + void hasTextAtLestOnce(String text, {bool hasWidget = true}) { + final textWidget = find.text(text); + expect(textWidget, hasWidget ? findsAny : findsNothing); + } + void hasType<T>() { final typeWidget = find.byType(T); expect(typeWidget, findsOneWidget); diff --git a/integration_test/components/common_test_flows.dart b/integration_test/components/common_test_flows.dart index 8350b5859..c9e605339 100644 --- a/integration_test/components/common_test_flows.dart +++ b/integration_test/components/common_test_flows.dart @@ -1,3 +1,5 @@ +import 'dart:io'; + import 'package:cake_wallet/entities/seed_type.dart'; import 'package:cake_wallet/reactions/bip39_wallet_utils.dart'; import 'package:cake_wallet/wallet_types.g.dart'; @@ -85,6 +87,7 @@ class CommonTestFlows { await _confirmPreSeedInfo(); await _confirmWalletDetails(); + await _commonTestCases.defaultSleepTime(); } //* ========== Handles flow from welcome to restoring wallet from seeds =============== @@ -168,8 +171,8 @@ class CommonTestFlows { await _walletListPageRobot.navigateToRestoreWalletOptionsPage(); await _commonTestCases.defaultSleepTime(); - await _restoreOptionsPageRobot.navigateToRestoreFromSeedsOrKeysPage(); - await _commonTestCases.defaultSleepTime(); + if (!Platform.isLinux) await _restoreOptionsPageRobot.navigateToRestoreFromSeedsOrKeysPage(); + if (!Platform.isLinux) await _commonTestCases.defaultSleepTime(); await _selectWalletTypeForWallet(walletType); await _commonTestCases.defaultSleepTime(); @@ -180,6 +183,7 @@ class CommonTestFlows { //* ========== Handles setting up pin code for wallet on first install =============== Future<void> setupPinCodeForWallet(List<int> pin) async { + if (Platform.isLinux) return; // ----------- SetupPinCode Page ------------- // Confirm initial defaults - Widgets to be displayed etc await _setupPinCodeRobot.isSetupPinCodePage(); @@ -212,7 +216,7 @@ class CommonTestFlows { await _welcomePageRobot.navigateToRestoreWalletPage(); - await _restoreOptionsPageRobot.navigateToRestoreFromSeedsOrKeysPage(); + if (!Platform.isLinux) await _restoreOptionsPageRobot.navigateToRestoreFromSeedsOrKeysPage(); await _selectWalletTypeForWallet(walletTypeToRestore); } @@ -234,6 +238,12 @@ class CommonTestFlows { await _newWalletPageRobot.generateWalletName(); + if (Platform.isLinux) { + // manual pin input + await _restoreFromSeedOrKeysPageRobot.enterPasswordForWalletRestore(CommonTestConstants.pin.join("")); + await _restoreFromSeedOrKeysPageRobot.enterPasswordRepeatForWalletRestore(CommonTestConstants.pin.join("")); + } + await _newWalletPageRobot.onNextButtonPressed(); } @@ -252,11 +262,15 @@ class CommonTestFlows { _walletSeedPageRobot.confirmWalletSeedReminderDisplays(); - await _walletSeedPageRobot.onCopySeedsButtonPressed(); + // await _walletSeedPageRobot.onCopySeedsButtonPressed(); - await _walletSeedPageRobot.onNextButtonPressed(); - - await _walletSeedPageRobot.onConfirmButtonOnSeedAlertDialogPressed(); + await _walletSeedPageRobot.onSeedPageVerifyButtonPressed(); + // Turns out the popup about "Copied to clipboard" prevents + //the button from being pressed on the first try, by just + //tapping it again we fix it. + // await _walletSeedPageRobot.onSeedPageVerifyButtonPressed(); + + await _walletSeedPageRobot.onOpenWalletButtonPressed(); } //* Main Restore Actions - On the RestoreFromSeed/Keys Page - Restore from Seeds Action @@ -277,6 +291,12 @@ class CommonTestFlows { .enterBlockHeightForWalletRestore(secrets.moneroTestWalletBlockHeight); } + if (Platform.isLinux) { + // manual pin input + await _restoreFromSeedOrKeysPageRobot.enterPasswordForWalletRestore(CommonTestConstants.pin.join("")); + await _restoreFromSeedOrKeysPageRobot.enterPasswordRepeatForWalletRestore(CommonTestConstants.pin.join("")); + } + await _restoreFromSeedOrKeysPageRobot.onRestoreWalletButtonPressed(); } diff --git a/integration_test/funds_related_tests.dart b/integration_test/funds_related_tests.dart index db24fbc0b..27187dc2f 100644 --- a/integration_test/funds_related_tests.dart +++ b/integration_test/funds_related_tests.dart @@ -67,6 +67,11 @@ void main() { await authPageRobot.enterPinCode(CommonTestConstants.pin); } + final onAuthPageDesktop = authPageRobot.onAuthPageDesktop(); + if (onAuthPageDesktop) { + await authPageRobot.enterPassword(CommonTestConstants.pin.join("")); + } + // ----------- Exchange Confirm Page ------------- await exchangeConfirmPageRobot.isExchangeConfirmPage(); diff --git a/integration_test/robots/auth_page_robot.dart b/integration_test/robots/auth_page_robot.dart index 6358d4398..2f5c43627 100644 --- a/integration_test/robots/auth_page_robot.dart +++ b/integration_test/robots/auth_page_robot.dart @@ -20,6 +20,11 @@ class AuthPageRobot extends PinCodeWidgetRobot { return hasPin; } + bool onAuthPageDesktop() { + final hasWalletPasswordInput = find.byKey(ValueKey('enter_wallet_password')); + return hasWalletPasswordInput.tryEvaluate(); + } + Future<void> isAuthPage() async { await commonTestCases.isSpecificPage<AuthPage>(); } diff --git a/integration_test/robots/pin_code_widget_robot.dart b/integration_test/robots/pin_code_widget_robot.dart index 18dc5fba4..62e606703 100644 --- a/integration_test/robots/pin_code_widget_robot.dart +++ b/integration_test/robots/pin_code_widget_robot.dart @@ -24,6 +24,20 @@ class PinCodeWidgetRobot { commonTestCases.hasValueKey('pin_code_button_0_key'); } + Future<void> enterPassword(String password, {int pumpDuration = 100}) async { + await commonTestCases.enterText( + password, + 'enter_wallet_password', + ); + await tester.pumpAndSettle(); + await commonTestCases.tapItemByKey( + 'unlock', + ); + await tester.pumpAndSettle(); + + await commonTestCases.defaultSleepTime(); + } + Future<void> enterPinCode(List<int> pinCode, {int pumpDuration = 100}) async { for (int pin in pinCode) { await commonTestCases.tapItemByKey( diff --git a/integration_test/robots/restore_from_seed_or_key_robot.dart b/integration_test/robots/restore_from_seed_or_key_robot.dart index 9d973061b..015a9e46f 100644 --- a/integration_test/robots/restore_from_seed_or_key_robot.dart +++ b/integration_test/robots/restore_from_seed_or_key_robot.dart @@ -1,7 +1,9 @@ import 'package:cake_wallet/entities/seed_type.dart'; import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/src/screens/restore/wallet_restore_page.dart'; +import 'package:cake_wallet/src/widgets/seed_widget.dart'; import 'package:cake_wallet/src/widgets/validable_annotated_editable_text.dart'; +import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import '../components/common_test_cases.dart'; @@ -65,12 +67,28 @@ class RestoreFromSeedOrKeysPageRobot { Future<void> enterSeedPhraseForWalletRestore(String text) async { ValidatableAnnotatedEditableTextState seedTextState = - await tester.state(find.byType(ValidatableAnnotatedEditableText)); + await tester.state(find.byType(ValidatableAnnotatedEditableText)); seedTextState.widget.controller.text = text; await tester.pumpAndSettle(); } + Future<void> enterPasswordForWalletRestore(String text) async { + await commonTestCases.enterText( + text, + 'password', + ); + await tester.pumpAndSettle(); + } + + Future<void> enterPasswordRepeatForWalletRestore(String text) async { + await commonTestCases.enterText( + text, + 'repeat_wallet_password', + ); + await tester.pumpAndSettle(); + } + Future<void> enterBlockHeightForWalletRestore(String blockHeight) async { await commonTestCases.enterText( blockHeight, diff --git a/integration_test/robots/send_page_robot.dart b/integration_test/robots/send_page_robot.dart index f8e1a49ad..b705c803f 100644 --- a/integration_test/robots/send_page_robot.dart +++ b/integration_test/robots/send_page_robot.dart @@ -183,32 +183,15 @@ class SendPageRobot { } Future<void> _handleAuthPage() async { - tester.printToConsole('Inside _handleAuth'); - await tester.pump(); - tester.printToConsole('starting auth checks'); - - final authPage = authPageRobot.onAuthPage(); - - tester.printToConsole('hasAuth:$authPage'); - - if (authPage) { - await tester.pump(); - tester.printToConsole('Starting inner _handleAuth loop checks'); - - try { - await authPageRobot.enterPinCode(CommonTestConstants.pin, pumpDuration: 500); - tester.printToConsole('Auth done'); - - await tester.pump(); - - tester.printToConsole('Auth pump done'); - } catch (e) { - tester.printToConsole('Auth failed, retrying'); - await tester.pump(); - _handleAuthPage(); - } + final onAuthPage = authPageRobot.onAuthPage(); + if (onAuthPage) { + await authPageRobot.enterPinCode(CommonTestConstants.pin); + } + + final onAuthPageDesktop = authPageRobot.onAuthPageDesktop(); + if (onAuthPageDesktop) { + await authPageRobot.enterPassword(CommonTestConstants.pin.join("")); } - await tester.pump(); } Future<void> handleSendResult() async { @@ -221,7 +204,7 @@ class SendPageRobot { tester.printToConsole('Has an Error in the handle: $hasError'); - int maxRetries = 20; + int maxRetries = 3; int retries = 0; while (hasError && retries < maxRetries) { diff --git a/integration_test/robots/wallet_seed_page_robot.dart b/integration_test/robots/wallet_seed_page_robot.dart index d52f3b1ec..576bff0d6 100644 --- a/integration_test/robots/wallet_seed_page_robot.dart +++ b/integration_test/robots/wallet_seed_page_robot.dart @@ -14,8 +14,13 @@ class WalletSeedPageRobot { await commonTestCases.isSpecificPage<WalletSeedPage>(); } - Future<void> onNextButtonPressed() async { - await commonTestCases.tapItemByKey('wallet_seed_page_next_button_key'); + Future<void> onSeedPageVerifyButtonPressed() async { + await commonTestCases.tapItemByKey('wallet_seed_page_verify_seed_button_key'); + await commonTestCases.defaultSleepTime(); + } + + Future<void> onOpenWalletButtonPressed() async { + await commonTestCases.tapItemByKey('wallet_seed_page_open_wallet_button_key'); await commonTestCases.defaultSleepTime(); } @@ -38,11 +43,14 @@ class WalletSeedPageRobot { final walletSeeds = walletSeedViewModel.seed; commonTestCases.hasText(walletName); - commonTestCases.hasText(walletSeeds); + final seedList = walletSeeds.trim().split(" "); + for (final seedWord in seedList) { + commonTestCases.hasTextAtLestOnce(seedWord); + } } void confirmWalletSeedReminderDisplays() { - commonTestCases.hasText(S.current.seed_reminder); + commonTestCases.hasText(S.current.cake_seeds_save_disclaimer); } Future<void> onSaveSeedsButtonPressed() async { diff --git a/integration_test/test_suites/confirm_seeds_flow_test.dart b/integration_test/test_suites/confirm_seeds_flow_test.dart index 2d11a2cc4..a62ce3f60 100644 --- a/integration_test/test_suites/confirm_seeds_flow_test.dart +++ b/integration_test/test_suites/confirm_seeds_flow_test.dart @@ -1,9 +1,13 @@ +import 'dart:io'; + import 'package:cake_wallet/wallet_types.g.dart'; import 'package:cw_core/wallet_type.dart'; import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:integration_test/integration_test.dart'; +import '../components/common_test_cases.dart'; import '../components/common_test_constants.dart'; import '../components/common_test_flows.dart'; import '../robots/auth_page_robot.dart'; @@ -95,6 +99,10 @@ Future<void> _confirmSeedsFlowForWalletType( await authPageRobot.enterPinCode(CommonTestConstants.pin); } + final onAuthPageDesktop = authPageRobot.onAuthPageDesktop(); + if (onAuthPageDesktop) { + await authPageRobot.enterPassword(CommonTestConstants.pin.join("")); + } await tester.pumpAndSettle(); await walletKeysAndSeedPageRobot.isWalletKeysAndSeedPage(); diff --git a/integration_test/test_suites/exchange_flow_test.dart b/integration_test/test_suites/exchange_flow_test.dart index c36ef9396..8ec2e54e7 100644 --- a/integration_test/test_suites/exchange_flow_test.dart +++ b/integration_test/test_suites/exchange_flow_test.dart @@ -56,6 +56,10 @@ void main() { await authPageRobot.enterPinCode(CommonTestConstants.pin); } + final onAuthPageDesktop = authPageRobot.onAuthPageDesktop(); + if (onAuthPageDesktop) { + await authPageRobot.enterPassword(CommonTestConstants.pin.join("")); + } await exchangeConfirmPageRobot.onSavedTradeIdButtonPressed(); await exchangeTradePageRobot.onGotItButtonPressed(); }); diff --git a/integration_test/test_suites/restore_wallet_through_seeds_flow_test.dart b/integration_test/test_suites/restore_wallet_through_seeds_flow_test.dart index a810aa722..0589d16ba 100644 --- a/integration_test/test_suites/restore_wallet_through_seeds_flow_test.dart +++ b/integration_test/test_suites/restore_wallet_through_seeds_flow_test.dart @@ -1,4 +1,7 @@ +import 'dart:io'; + import 'package:cake_wallet/wallet_types.g.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'package:cw_core/wallet_type.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; diff --git a/integration_test_runner.sh b/integration_test_runner.sh index 34c9227c0..86e28f0b8 100755 --- a/integration_test_runner.sh +++ b/integration_test_runner.sh @@ -1,4 +1,5 @@ #!/bin/bash +export DESKTOP_FORCE_MOBILE="Y" declare -a targets declare -a passed_tests @@ -12,6 +13,10 @@ done < <(find integration_test/test_suites -name "*.dart" -type f -print0) # Run each test and collect results for target in "${targets[@]}" do + if [[ "x$REMOVE_DATA_DIRECTORY" == "xY" ]]; + then + rm -rf ~/.local/share/com.example.cake_wallet ~/Documents/cake_wallet + fi echo "Running test: $target" if flutter drive \ --driver=test_driver/integration_test.dart \ diff --git a/lib/src/screens/new_wallet/new_wallet_page.dart b/lib/src/screens/new_wallet/new_wallet_page.dart index e63a01f61..e2d5a953c 100644 --- a/lib/src/screens/new_wallet/new_wallet_page.dart +++ b/lib/src/screens/new_wallet/new_wallet_page.dart @@ -221,6 +221,7 @@ class _WalletNameFormState extends State<WalletNameForm> { ), if (_walletNewVM.hasWalletPassword) ...[ TextFormField( + key: ValueKey('password'), onChanged: (value) => _walletNewVM.walletPassword = value, controller: _passwordController, textAlign: TextAlign.center, @@ -257,6 +258,7 @@ class _WalletNameFormState extends State<WalletNameForm> { ), ), TextFormField( + key: ValueKey('repeat_wallet_password'), onChanged: (value) => _walletNewVM.repeatedWalletPassword = value, controller: _repeatedPasswordController, textAlign: TextAlign.center, diff --git a/lib/src/screens/restore/wallet_restore_from_keys_form.dart b/lib/src/screens/restore/wallet_restore_from_keys_form.dart index 83772f866..0c9af6910 100644 --- a/lib/src/screens/restore/wallet_restore_from_keys_form.dart +++ b/lib/src/screens/restore/wallet_restore_from_keys_form.dart @@ -148,12 +148,14 @@ class WalletRestoreFromKeysFromState extends State<WalletRestoreFromKeysFrom> { ), if (widget.displayWalletPassword) ...[Container( + key: ValueKey('password'), padding: EdgeInsets.only(top: 20.0), child: BaseTextFormField( controller: passwordTextEditingController, hintText: S.of(context).password, obscureText: true)), Container( + key: ValueKey('repeat_wallet_password'), padding: EdgeInsets.only(top: 20.0), child: BaseTextFormField( controller: repeatedPasswordTextEditingController, diff --git a/lib/src/screens/restore/wallet_restore_from_seed_form.dart b/lib/src/screens/restore/wallet_restore_from_seed_form.dart index 1684f6f92..6a493087b 100644 --- a/lib/src/screens/restore/wallet_restore_from_seed_form.dart +++ b/lib/src/screens/restore/wallet_restore_from_seed_form.dart @@ -223,12 +223,14 @@ class WalletRestoreFromSeedFormState extends State<WalletRestoreFromSeedForm> { ), if (widget.displayWalletPassword) ...[BaseTextFormField( + key: ValueKey('password'), controller: passwordTextEditingController, hintText: S .of(context) .password, obscureText: true), BaseTextFormField( + key: ValueKey('repeat_wallet_password'), controller: repeatedPasswordTextEditingController, hintText: S .of(context) diff --git a/lib/src/screens/wallet_unlock/wallet_unlock_page.dart b/lib/src/screens/wallet_unlock/wallet_unlock_page.dart index 3e6966f9d..4afbfe2c1 100644 --- a/lib/src/screens/wallet_unlock/wallet_unlock_page.dart +++ b/lib/src/screens/wallet_unlock/wallet_unlock_page.dart @@ -170,6 +170,7 @@ class WalletUnlockPageState extends AuthPageState<WalletUnlockPage> { SizedBox(height: 24), Form( child: TextFormField( + key: ValueKey('enter_wallet_password'), onChanged: (value) => null, controller: _passwordController, textAlign: TextAlign.center, @@ -205,6 +206,7 @@ class WalletUnlockPageState extends AuthPageState<WalletUnlockPage> { ), ), Padding( + key: ValueKey('unlock'), padding: EdgeInsets.only(bottom: 24), child: Observer( builder: (_) => LoadingPrimaryButton( diff --git a/linux/my_application.cc b/linux/my_application.cc index 49ed75499..49f9ae139 100644 --- a/linux/my_application.cc +++ b/linux/my_application.cc @@ -46,8 +46,11 @@ static void my_application_activate(GApplication* application) { } else { gtk_window_set_title(window, "Cake Wallet"); } - - gtk_window_set_default_size(window, 1280, 720); + if (getenv("DESKTOP_FORCE_MOBILE")) { + gtk_window_set_default_size(window, 720, 1280); + } else { + gtk_window_set_default_size(window, 1280, 720); + } gtk_widget_show(GTK_WIDGET(window)); g_autoptr(FlDartProject) project = fl_dart_project_new(); diff --git a/model_generator.sh b/model_generator.sh index 730817c24..1443b0fc9 100755 --- a/model_generator.sh +++ b/model_generator.sh @@ -1,18 +1,24 @@ #!/bin/bash set -x -e -cd cw_core; flutter pub get; dart run build_runner build --delete-conflicting-outputs; cd .. -cd cw_evm; flutter pub get; dart run build_runner build --delete-conflicting-outputs; cd .. -cd cw_monero; flutter pub get; dart run build_runner build --delete-conflicting-outputs; cd .. -cd cw_bitcoin; flutter pub get; dart run build_runner build --delete-conflicting-outputs; cd .. -cd cw_haven; flutter pub get; dart run build_runner build --delete-conflicting-outputs; cd .. -cd cw_nano; flutter pub get; dart run build_runner build --delete-conflicting-outputs; cd .. -cd cw_bitcoin_cash; flutter pub get; dart run build_runner build --delete-conflicting-outputs; cd .. -cd cw_solana; flutter pub get; dart run build_runner build --delete-conflicting-outputs; cd .. -cd cw_tron; flutter pub get; dart run build_runner build --delete-conflicting-outputs; cd .. -cd cw_wownero; flutter pub get; dart run build_runner build --delete-conflicting-outputs; cd .. -cd cw_polygon; flutter pub get; cd .. -cd cw_ethereum; flutter pub get; cd .. -cd cw_mweb && flutter pub get && cd .. -dart run build_runner build --delete-conflicting-outputs +for cwcoin in cw_{core,evm,monero,bitcoin,haven,nano,bitcoin_cash,solana,tron,wownero} +do + if [[ "x$1" == "xasync" ]]; + then + bash -c "cd $cwcoin; flutter pub get; dart run build_runner build --delete-conflicting-outputs; cd .." & + else + bash -c "cd $cwcoin; flutter pub get; dart run build_runner build --delete-conflicting-outputs; cd .." + fi +done +for cwcoin in cw_{polygon,ethereum,mwebd}; +do + if [[ "x$1" == "xasync" ]]; + then + bash -c "cd $cwcoin; flutter pub get; cd .." & + else + bash -c "cd $cwcoin; flutter pub get; cd .." + fi +done +flutter pub get +dart run build_runner build --delete-conflicting-outputs diff --git a/scripts/android/.gitignore b/scripts/android/.gitignore new file mode 100644 index 000000000..f7e94b7c0 --- /dev/null +++ b/scripts/android/.gitignore @@ -0,0 +1 @@ +mwebd \ No newline at end of file diff --git a/scripts/android/build_monero_all.sh b/scripts/android/build_monero_all.sh index 261ebd560..71a6b6228 100755 --- a/scripts/android/build_monero_all.sh +++ b/scripts/android/build_monero_all.sh @@ -8,50 +8,20 @@ cd "$(dirname "$0")" NPROC="-j$(nproc)" -if [[ "x$(uname)" == "xDarwin" ]]; -then - USE_DOCKER="ON" - NPROC="-j1" -fi - ../prepare_moneroc.sh -if [[ ! "x$RUNNER_OS" == "x" ]]; -then - REMOVE_CACHES=ON -fi - -# NOTE: -j1 is intentional. Otherwise you will run into weird behaviour on macos -if [[ ! "x$USE_DOCKER" == "x" ]]; -then - for COIN in monero wownero; - do - pushd ../monero_c - docker run --platform linux/amd64 -v$HOME/.cache/ccache:/root/.ccache -v$PWD:$PWD -w $PWD --rm -it git.mrcyjanek.net/mrcyjanek/debian:buster bash -c "git config --global --add safe.directory '*'; apt update; apt install -y ccache gcc g++ libtinfo5 gperf; ./build_single.sh ${COIN} x86_64-linux-android $NPROC" - # docker run --platform linux/amd64 -v$PWD:$PWD -w $PWD --rm -it git.mrcyjanek.net/mrcyjanek/debian:buster bash -c "git config --global --add safe.directory '*'; apt update; apt install -y ccache gcc g++ libtinfo5 gperf; ./build_single.sh ${COIN} i686-linux-android $NPROC" - docker run --platform linux/amd64 -v$HOME/.cache/ccache:/root/.ccache -v$PWD:$PWD -w $PWD --rm -it git.mrcyjanek.net/mrcyjanek/debian:buster bash -c "git config --global --add safe.directory '*'; apt update; apt install -y ccache gcc g++ libtinfo5 gperf; ./build_single.sh ${COIN} armv7a-linux-androideabi $NPROC" - docker run --platform linux/amd64 -v$HOME/.cache/ccache:/root/.ccache -v$PWD:$PWD -w $PWD --rm -it git.mrcyjanek.net/mrcyjanek/debian:buster bash -c "git config --global --add safe.directory '*'; apt update; apt install -y ccache gcc g++ libtinfo5 gperf; ./build_single.sh ${COIN} aarch64-linux-android $NPROC" - popd - done -else - for COIN in monero wownero; - do - pushd ../monero_c - env -i ./build_single.sh ${COIN} x86_64-linux-android $NPROC - [[ ! "x$REMOVE_CACHES" == "x" ]] && rm -rf ${COIN}/contrib/depends/x86_64-linux-android - # ./build_single.sh ${COIN} i686-linux-android $NPROC - # [[ ! "x$REMOVE_CACHES" == "x" ]] && rm -rf ${COIN}/contrib/depends/i686-linux-android - env -i ./build_single.sh ${COIN} armv7a-linux-androideabi $NPROC - [[ ! "x$REMOVE_CACHES" == "x" ]] && rm -rf ${COIN}/contrib/depends/armv7a-linux-androideabi - env -i ./build_single.sh ${COIN} aarch64-linux-android $NPROC - [[ ! "x$REMOVE_CACHES" == "x" ]] && rm -rf ${COIN}/contrib/depends/aarch64-linux-android - - popd - unxz -f ../monero_c/release/${COIN}/x86_64-linux-android_libwallet2_api_c.so.xz - - unxz -f ../monero_c/release/${COIN}/armv7a-linux-androideabi_libwallet2_api_c.so.xz - - unxz -f ../monero_c/release/${COIN}/aarch64-linux-android_libwallet2_api_c.so.xz - [[ ! "x$REMOVE_CACHES" == "x" ]] && rm -rf ${COIN}/contrib/depends/{built,sources} - done -fi +for COIN in monero wownero; +do + pushd ../monero_c + for target in {x86_64,aarch64}-linux-android armv7a-linux-androideabi + do + if [[ -f "release/${COIN}/${target}_libwallet2_api_c.so" ]]; + then + echo "file exist, not building monero_c for ${COIN}/$target."; + else + env -i ./build_single.sh ${COIN} $target $NPROC + unxz -f ../monero_c/release/${COIN}/${target}_libwallet2_api_c.so.xz + fi + done + popd +done \ No newline at end of file diff --git a/scripts/android/build_mwebd.sh b/scripts/android/build_mwebd.sh index 4434e30f1..cd4e2c1f4 100755 --- a/scripts/android/build_mwebd.sh +++ b/scripts/android/build_mwebd.sh @@ -16,7 +16,4 @@ cd mwebd git reset --hard 555349415f76a42ec5c76152b64c4ab9aabc448f gomobile bind -target=android -androidapi 21 . mkdir -p ../../../cw_mweb/android/libs/ -mv ./mwebd.aar $_ -# cleanup: -cd .. -rm -rf mwebd \ No newline at end of file +cp ./mwebd.aar $_ \ No newline at end of file diff --git a/scripts/linux/Dockerfile.linux b/scripts/linux/Dockerfile.linux new file mode 100644 index 000000000..c8f4d3bde --- /dev/null +++ b/scripts/linux/Dockerfile.linux @@ -0,0 +1,148 @@ +# Usage: +# docker build . -f Dockerfile.linux -t ghcr.io/cake-tech/cake_wallet:main-linux +# docker push ghcr.io/cake-tech/cake_wallet:main-linux + +FROM --platform=linux/amd64 docker.io/debian:12 + +LABEL org.opencontainers.image.source=https://github.com/cake-tech/cake_wallet + +ENV GOLANG_VERSION=1.23.4 +# comes from https://developer.android.com/studio/#command-tools +ENV ANDROID_SDK_TOOLS_VERSION=11076708 +# https://developer.android.com/studio/releases/build-tools +ENV ANDROID_PLATFORM_VERSION=34 +ENV ANDROID_BUILD_TOOLS_VERSION=34.0.0 + +ENV FLUTTER_VERSION=3.24.0 + +# If we ever need to migrate the home directory... +RUN sed -i 's|^root:[^:]*:[^:]*:[^:]*:[^:]*:/root:|root:x:0:0:root:/root:|' /etc/passwd +# mkdir -p /root && rm -rf /root && cp -a /root /root +ENV HOME=/root +# Heavily inspired by cirrusci images +# https://github.com/cirruslabs/docker-images-android/blob/master/sdk/tools/Dockerfile +# https://github.com/cirruslabs/docker-images-android/blob/master/sdk/34/Dockerfile +# https://github.com/cirruslabs/docker-images-android/blob/master/sdk/34-ndk/Dockerfile +# https://github.com/cirruslabs/docker-images-flutter/blob/master/sdk/Dockerfile + +ENV ANDROID_HOME=/opt/android-sdk-linux \ + LANG=en_US.UTF-8 \ + LC_ALL=en_US.UTF-8 \ + LANGUAGE=en_US:en + +ENV ANDROID_SDK_ROOT=$ANDROID_HOME \ + PATH=${PATH}:${ANDROID_HOME}/cmdline-tools/latest/bin:${ANDROID_HOME}/platform-tools:${ANDROID_HOME}/emulator + +RUN set -o xtrace \ + && cd /opt \ + && apt-get update \ + && apt-get upgrade -y \ + && apt-get install -y jq \ + && apt-get install -y default-jdk \ + && apt-get install -y sudo wget zip unzip git openssh-client curl bc software-properties-common build-essential ruby-full ruby-bundler libstdc++6 libpulse0 libglu1-mesa locales lcov libsqlite3-dev --no-install-recommends \ + # for x86 emulators + && apt-get install -y libxtst6 libnss3-dev libnspr4 libxss1 libatk-bridge2.0-0 libgtk-3-0 libgdk-pixbuf2.0-0 \ + && apt-get install -y -qq xxd \ + && apt-get install -y lftp \ + && apt-get install -qq -y sqlite3 libsqlite3-dev \ + # linux desktop dependencies + && apt-get install -y clang cmake ninja-build pkg-config libgtk-3-dev \ + # monero_c dependencies + && apt-get install -y ccache build-essential autoconf libtool gperf llvm \ + # extra stuff for KVM + && apt-get install -y udev qemu-kvm libvirt-daemon-system libvirt-clients bridge-utils \ + # for linux tests + && apt-get install -y xvfb network-manager ffmpeg x11-utils \ + && rm -rf /var/lib/apt/lists/* \ + && sh -c 'echo "en_US.UTF-8 UTF-8" > /etc/locale.gen' \ + && locale-gen \ + && update-locale LANG=en_US.UTF-8 + +# install nodejs for actions +RUN apt-get update && \ + apt-get install -y curl && \ + curl -fsSL https://deb.nodesource.com/setup_23.x | bash - && \ + apt-get install -y nodejs && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* + +RUN wget https://go.dev/dl/go${GOLANG_VERSION}.linux-amd64.tar.gz &&\ + rm -rf /usr/local/go &&\ + tar -C /usr/local -xzf go${GOLANG_VERSION}.linux-amd64.tar.gz + +ENV PATH=${PATH}:/usr/local/go/bin:${HOME}/go/bin +ENV GOROOT=/usr/local/go +ENV GOPATH=${HOME}/go +RUN go install golang.org/x/mobile/cmd/gomobile@latest +RUN gomobile init + +RUN wget -q https://dl.google.com/android/repository/commandlinetools-linux-${ANDROID_SDK_TOOLS_VERSION}_latest.zip -O android-sdk-tools.zip \ + && mkdir -p ${ANDROID_HOME}/cmdline-tools/ \ + && unzip -q android-sdk-tools.zip -d ${ANDROID_HOME}/cmdline-tools/ \ + && mv ${ANDROID_HOME}/cmdline-tools/cmdline-tools ${ANDROID_HOME}/cmdline-tools/latest \ + && chown -R root:root $ANDROID_HOME \ + && rm android-sdk-tools.zip \ + && echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers \ + && yes | sdkmanager --licenses \ + && wget -O /usr/bin/android-wait-for-emulator https://raw.githubusercontent.com/travis-ci/travis-cookbooks/master/community-cookbooks/android-sdk/files/default/android-wait-for-emulator \ + && chmod +x /usr/bin/android-wait-for-emulator \ + && sdkmanager platform-tools \ + && mkdir -p ${HOME}/.android \ + && touch ${HOME}/.android/repositories.cfg \ + && git config --global user.email "czarek@cakewallet.com" \ + && git config --global user.name "CakeWallet CI" + +# emulator is not available on linux/arm64 (https://issuetracker.google.com/issues/227219818) +RUN if [ $(uname -m) == "x86_64" ]; then sdkmanager emulator ; fi + +# Extra dependencies to not download them for cake wallet build +RUN yes | sdkmanager \ + "platforms;android-$ANDROID_PLATFORM_VERSION" \ + "build-tools;$ANDROID_BUILD_TOOLS_VERSION" \ + "platforms;android-33" \ + "build-tools;33.0.2" \ + "build-tools;33.0.1" \ + "build-tools;33.0.0" \ + "build-tools;35.0.0" + +ENV ANDROID_NDK_VERSION=27.2.12479018 + +# Extra ndk dependency for sp_scanner +RUN yes | sdkmanager "ndk;$ANDROID_NDK_VERSION" \ + "ndk;27.0.12077973" + +# https://github.com/ReactiveCircus/android-emulator-runner dependencies for tests +RUN yes | sdkmanager "system-images;android-29;default;x86" \ + "system-images;android-29;default;x86_64" \ + "system-images;android-31;default;x86_64" \ + "platforms;android-29" + +# fake the KVM status so android emulator doesn't complain (that much) +RUN (addgroup kvm || true) && \ + adduser root kvm && \ + mkdir -p /etc/udev/rules.d/ && \ + echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | tee /etc/udev/rules.d/99-kvm4all.rules + +ENV PATH=${HOME}/.cargo/bin:${PATH} + +RUN curl https://sh.rustup.rs -sSf | bash -s -- -y && \ + cargo install cargo-ndk && \ + for target in aarch64-linux-android armv7-linux-androideabi i686-linux-android x86_64-linux-android x86_64-unknown-linux-gnu; \ + do \ + rustup target add --toolchain stable $target; \ + done + + +ENV HOME=${HOME} +ENV FLUTTER_HOME=${HOME}/sdks/flutter/${FLUTTER_VERSION} +ENV FLUTTER_ROOT=$FLUTTER_HOME + +ENV PATH=${PATH}:${FLUTTER_HOME}/bin:${FLUTTER_HOME}/bin/cache/dart-sdk/bin + +RUN git clone --depth 1 --branch ${FLUTTER_VERSION} https://github.com/flutter/flutter.git ${FLUTTER_HOME} + +RUN yes | flutter doctor --android-licenses \ + && flutter doctor \ + && chown -R root:root ${FLUTTER_HOME} + +RUN flutter precache diff --git a/scripts/linux/build_monero_all.sh b/scripts/linux/build_monero_all.sh index 5dc512527..558423219 100755 --- a/scripts/linux/build_monero_all.sh +++ b/scripts/linux/build_monero_all.sh @@ -1,9 +1,5 @@ #!/bin/bash - -. ./config.sh - - set -x -e cd "$(dirname "$0")" @@ -15,7 +11,15 @@ NPROC="-j$(nproc)" for COIN in monero wownero; do pushd ../monero_c - ./build_single.sh ${COIN} $(gcc -dumpmachine) $NPROC + for target in x86_64-linux-gnu + do + if [[ -f "release/${COIN}/${target}_libwallet2_api_c.so" ]]; + then + echo "file exist, not building monero_c for ${COIN}/$target."; + else + ./build_single.sh ${COIN} $target $NPROC + unxz -f ../monero_c/release/${COIN}/${target}_libwallet2_api_c.so.xz + fi + done popd - unxz -f ../monero_c/release/${COIN}/$(gcc -dumpmachine)_libwallet2_api_c.so.xz -done +done \ No newline at end of file diff --git a/scripts/prepare_moneroc.sh b/scripts/prepare_moneroc.sh index c345408dd..c0de33f6f 100755 --- a/scripts/prepare_moneroc.sh +++ b/scripts/prepare_moneroc.sh @@ -4,9 +4,9 @@ set -x -e cd "$(dirname "$0")" -if [[ ! -d "monero_c" ]]; +if [[ ! -d "monero_c/.git" ]]; then - git clone https://github.com/mrcyjanek/monero_c --branch master + git clone https://github.com/mrcyjanek/monero_c --branch master monero_c cd monero_c git checkout af5277f96073917185864d3596e82b67bee54e78 git reset --hard diff --git a/scripts/windows/.gitignore b/scripts/windows/.gitignore new file mode 100644 index 000000000..bb28076cd --- /dev/null +++ b/scripts/windows/.gitignore @@ -0,0 +1 @@ +actions-runner \ No newline at end of file diff --git a/scripts/windows/Dockerfile.windows b/scripts/windows/Dockerfile.windows new file mode 100644 index 000000000..f2a08b41c --- /dev/null +++ b/scripts/windows/Dockerfile.windows @@ -0,0 +1,68 @@ +# Usage: +# docker build . -f Dockerfile.windows -t ghcr.io/cake-tech/cake_wallet:main-windows +# docker push ghcr.io/cake-tech/cake_wallet:main-windows + +FROM mcr.microsoft.com/windows/servercore:ltsc2022 + +ENV FLUTTER_VERSION=3.24.0 +ENV GIT_VERSION=2.47.1 +ENV VS_INSTALLED_DIR="C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools" +ENV PATH="C:\Users\ContainerAdministrator\.cargo\bin;C:\ProgramData\chocolatey\bin;C:\flutter\flutter\bin;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Windows\System32\OpenSSH\;C:\Users\ContainerAdministrator\AppData\Local\Microsoft\WindowsApps" +ENV RUNNER_VERSION=2.321.0 +ENV RUNNER_URL=https://github.com/actions/runner/releases/download/v${RUNNER_VERSION}/actions-runner-win-x64-${RUNNER_VERSION}.zip +ENV RUNNER_WORKDIR=_work + +RUN powershell -Command \ + curl.exe -L https://aka.ms/vs/17/release/vc_redist.x64.exe -o vc_redist.x64.exe ; \ + Start-Process -Wait -FilePath .\vc_redist.x64.exe -ArgumentList '/quiet', '/install' ; \ + Remove-Item -Force vc_redist.x64.exe + +RUN powershell -Command \ + $GIT_VERSION = [Environment]::GetEnvironmentVariable('GIT_VERSION'); \ + curl.exe -L https://github.com/git-for-windows/git/releases/download/v$($GIT_VERSION).windows.1/Git-$($GIT_VERSION)-64-bit.exe -o git_installer.exe ; \ + Start-Process -Wait -FilePath .\git_installer.exe -ArgumentList '/SILENT', '/NOICONS' ; \ + Remove-Item -Force git_installer.exe + +RUN powershell -NoProfile -ExecutionPolicy Bypass -Command \ + Set-ExecutionPolicy RemoteSigned -Scope Process; \ + [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; \ + Invoke-WebRequest https://chocolatey.org/install.ps1 -UseBasicP -OutFile install.ps1; \ + powershell -NoProfile -ExecutionPolicy Bypass -File install.ps1; \ + Remove-Item -Force install.ps1 + +RUN choco install -y visualstudio2022community +RUN choco install -y visualstudio2022-workload-nativedesktop +RUN choco install -y nodejs +RUN choco install -y go +RUN choco install -y 7zip + +RUN powershell -Command \ + curl.exe -L https://win.rustup.rs -o rustup-init.exe; \ + Start-Process -Wait -FilePath .\rustup-init.exe -ArgumentList "-y"; \ + Remove-Item -Force .\rustup-init.exe + +RUN powershell -Command \ + curl.exe -L https://dist.nuget.org/win-x86-commandline/latest/nuget.exe -o C:\Windows\System32\nuget.exe + +RUN powershell -Command \ + $FLUTTER_VERSION = [Environment]::GetEnvironmentVariable('FLUTTER_VERSION'); \ + curl.exe -L https://storage.googleapis.com/flutter_infra_release/releases/stable/windows/flutter_windows_$($FLUTTER_VERSION)-stable.zip -o flutter.zip ; \ + 7z x flutter.zip -oC:\flutter -bsp1 -bse1 ; \ + Remove-Item -Force flutter.zip + +RUN flutter precache + +WORKDIR C:\\actions-runner + +RUN powershell -Command \ + curl.exe -L $env:RUNNER_URL -o 'actions-runner.zip'; \ + 7z x actions-runner.zip -oC:\actions-runner -bsp1 -bse1 ; \ + Remove-Item -Path 'actions-runner.zip' + +COPY actions-runner/.credentials /actions-runner/.credentials +COPY actions-runner/.credentials_rsaparams /actions-runner/.credentials_rsaparams +COPY actions-runner/.runner /actions-runner/.runner + +COPY ci_entrypoint.ps1 /actions-runner/ci_entrypoint.ps1 + +ENTRYPOINT ["powershell", "-File", "ci_entrypoint.ps1"] \ No newline at end of file diff --git a/scripts/windows/ci_entrypoint.ps1 b/scripts/windows/ci_entrypoint.ps1 new file mode 100644 index 000000000..d68d0f5ec --- /dev/null +++ b/scripts/windows/ci_entrypoint.ps1 @@ -0,0 +1,5 @@ +$runnerDir = "C:\actions-runner" +$runCmd = "$runnerDir\run.cmd" + +Write-Host "Starting the runner..." +& $runCmd \ No newline at end of file diff --git a/scripts/windows/ci_register.ps1 b/scripts/windows/ci_register.ps1 new file mode 100644 index 000000000..a39048cdb --- /dev/null +++ b/scripts/windows/ci_register.ps1 @@ -0,0 +1,30 @@ +# Variables for paths and config +$runnerDir = "C:\actions-runner" +$configCmd = "$runnerDir\config.cmd" +$runCmd = "$runnerDir\run.cmd" + +# Check required environment variables +if (-not $env:RUNNER_TOKEN) { + Write-Error "RUNNER_TOKEN is not set. Exiting." + exit 1 +} +if (-not $env:RUNNER_REPO_URL) { + Write-Error "RUNNER_REPO_URL is not set. Exiting." + exit 1 +} +$env:RUNNER_NAME = "windows-amd64-cake" +$env:RUNNER_WORKDIR = "_work" + +# Register the runner +Write-Host "Registering the runner..." +Write-Host "--url $env:RUNNER_REPO_URL" +Write-Host "--token $env:RUNNER_TOKEN" +Write-Host "--name $env:RUNNER_NAME" +Write-Host "--work $env:RUNNER_WORKDIR" + +& $configCmd --url $env:RUNNER_REPO_URL ` + --token $env:RUNNER_TOKEN ` + --name $env:RUNNER_NAME ` + --work $env:RUNNER_WORKDIR ` + --unattended ` + --replace \ No newline at end of file From f431091f5ee5dd1d945a668c787324b9d1e9fddc Mon Sep 17 00:00:00 2001 From: cyan <cyjan@mrcyjanek.net> Date: Wed, 15 Jan 2025 14:24:29 +0100 Subject: [PATCH 09/16] Hotfix CI (#1963) * [skip slack] It looks like during our sleep github decided to break artifact upload api.. * [skip slack] Name the artifact --- .github/workflows/pr_test_build_android.yml | 5 +++-- .github/workflows/pr_test_build_linux.yml | 6 ++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/.github/workflows/pr_test_build_android.yml b/.github/workflows/pr_test_build_android.yml index 2a7eec5c9..c5f875128 100644 --- a/.github/workflows/pr_test_build_android.yml +++ b/.github/workflows/pr_test_build_android.yml @@ -283,6 +283,7 @@ jobs: run: rm -rf build/app/outputs/flutter-apk/test-apk/ - name: Upload Artifact to github - uses: kittaakos/upload-artifact-as-is@v0 + uses: actions/upload-artifact@v4 with: - path: ${{ github.workspace }}/build/app/outputs/flutter-apk \ No newline at end of file + path: ${{ github.workspace }}/build/app/outputs/flutter-apk + name: "android apk" \ No newline at end of file diff --git a/.github/workflows/pr_test_build_linux.yml b/.github/workflows/pr_test_build_linux.yml index 6a29e4033..345c95c4f 100644 --- a/.github/workflows/pr_test_build_linux.yml +++ b/.github/workflows/pr_test_build_linux.yml @@ -221,9 +221,10 @@ jobs: popd - name: Upload Artifact to github - uses: kittaakos/upload-artifact-as-is@v0 + uses: actions/upload-artifact@v4 with: path: ${{ github.workspace }}/build/linux/x64/release/cakewallet_linux.zip + name: cakewallet_linux - name: Prepare virtual desktop if: ${{ contains(github.event.head_commit.message, 'run tests') }} @@ -292,6 +293,7 @@ jobs: - name: Upload Artifact to github if: always() continue-on-error: true - uses: kittaakos/upload-artifact-as-is@v0 + uses: actions/upload-artifact@v4 with: path: ${{ github.workspace }}/screen_grab.mkv.gpg + name: tests_screen_grab From f072bc8dce3b94acda037449b41297d2588aa71f Mon Sep 17 00:00:00 2001 From: cyan <cyjan@mrcyjanek.net> Date: Wed, 15 Jan 2025 22:15:42 +0100 Subject: [PATCH 10/16] Pin ledger_flutter_plus dependency to fix builds (#1965) --- pubspec_base.yaml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/pubspec_base.yaml b/pubspec_base.yaml index e87b5a44e..450977a40 100644 --- a/pubspec_base.yaml +++ b/pubspec_base.yaml @@ -107,7 +107,10 @@ dependencies: polyseed: ^0.0.6 nostr_tools: ^1.0.9 solana: ^0.31.0+1 - ledger_flutter_plus: ^1.4.1 + ledger_flutter_plus: + git: + url: https://github.com/vespr-wallet/ledger-flutter-plus + ref: c2e341d8038f1108690ad6f80f7b4b7156aacc76 hashlib: ^1.19.2 dev_dependencies: @@ -146,6 +149,10 @@ dependency_overrides: url: https://github.com/cake-tech/bitcoin_base ref: cake-update-v9 ffi: 2.1.0 + ledger_flutter_plus: + git: + url: https://github.com/vespr-wallet/ledger-flutter-plus + ref: c2e341d8038f1108690ad6f80f7b4b7156aacc76 flutter_icons: image_path: "assets/images/app_logo.png" From 60e7dcffa957278866829b3d9f3279d452da3e67 Mon Sep 17 00:00:00 2001 From: Matthew Fosse <matt@fosse.co> Date: Wed, 15 Jan 2025 17:03:30 -0500 Subject: [PATCH 11/16] .well-known domain support (#1956) * add well-known setting [wip] * should work * fix * minor fix (tested and working) --- lib/core/backup_service.dart | 6 ++ lib/entities/parse_address_from_domain.dart | 12 +++ lib/entities/parsed_address.dart | 11 ++- lib/entities/preferences_key.dart | 1 + lib/entities/wellknown_record.dart | 92 +++++++++++++++++++ .../widgets/extract_address_from_parsed.dart | 5 + .../screens/settings/domain_lookups_page.dart | 4 + lib/store/settings_store.dart | 11 +++ .../settings/privacy_settings_view_model.dart | 6 ++ 9 files changed, 147 insertions(+), 1 deletion(-) create mode 100644 lib/entities/wellknown_record.dart diff --git a/lib/core/backup_service.dart b/lib/core/backup_service.dart index f101ed7e1..03f20363d 100644 --- a/lib/core/backup_service.dart +++ b/lib/core/backup_service.dart @@ -293,6 +293,7 @@ class BackupService { final lookupsUnstoppableDomains = data[PreferencesKey.lookupsUnstoppableDomains] as bool?; final lookupsOpenAlias = data[PreferencesKey.lookupsOpenAlias] as bool?; final lookupsENS = data[PreferencesKey.lookupsENS] as bool?; + final lookupsWellKnown = data[PreferencesKey.lookupsWellKnown] as bool?; final syncAll = data[PreferencesKey.syncAllKey] as bool?; final syncMode = data[PreferencesKey.syncModeKey] as int?; final autoGenerateSubaddressStatus = @@ -403,6 +404,9 @@ class BackupService { if (lookupsENS != null) await _sharedPreferences.setBool(PreferencesKey.lookupsENS, lookupsENS); + if (lookupsWellKnown != null) + await _sharedPreferences.setBool(PreferencesKey.lookupsWellKnown, lookupsWellKnown); + if (syncAll != null) await _sharedPreferences.setBool(PreferencesKey.syncAllKey, syncAll); if (syncMode != null) await _sharedPreferences.setInt(PreferencesKey.syncModeKey, syncMode); @@ -542,6 +546,8 @@ class BackupService { _sharedPreferences.getBool(PreferencesKey.lookupsUnstoppableDomains), PreferencesKey.lookupsOpenAlias: _sharedPreferences.getBool(PreferencesKey.lookupsOpenAlias), PreferencesKey.lookupsENS: _sharedPreferences.getBool(PreferencesKey.lookupsENS), + PreferencesKey.lookupsWellKnown: + _sharedPreferences.getBool(PreferencesKey.lookupsWellKnown), PreferencesKey.syncModeKey: _sharedPreferences.getInt(PreferencesKey.syncModeKey), PreferencesKey.syncAllKey: _sharedPreferences.getBool(PreferencesKey.syncAllKey), PreferencesKey.autoGenerateSubaddressStatusKey: diff --git a/lib/entities/parse_address_from_domain.dart b/lib/entities/parse_address_from_domain.dart index b13dfa9ad..9be125081 100644 --- a/lib/entities/parse_address_from_domain.dart +++ b/lib/entities/parse_address_from_domain.dart @@ -5,6 +5,7 @@ import 'package:cake_wallet/entities/openalias_record.dart'; import 'package:cake_wallet/entities/parsed_address.dart'; import 'package:cake_wallet/entities/unstoppable_domain_address.dart'; import 'package:cake_wallet/entities/emoji_string_extension.dart'; +import 'package:cake_wallet/entities/wellknown_record.dart'; import 'package:cake_wallet/exchange/provider/thorchain_exchange.provider.dart'; import 'package:cake_wallet/mastodon/mastodon_api.dart'; import 'package:cake_wallet/nostr/nostr_api.dart'; @@ -208,6 +209,17 @@ class AddressResolver { } } + // .well-known scheme: + if (text.contains('.') && text.contains('@')) { + if (settingsStore.lookupsWellKnown) { + final record = + await WellKnownRecord.fetchAddressAndName(formattedName: text, currency: currency); + if (record != null) { + return ParsedAddress.fetchWellKnownAddress(address: record.address, name: text); + } + } + } + if (!text.startsWith('@') && text.contains('@') && !text.contains('.')) { final bool isFioRegistered = await FioAddressProvider.checkAvail(text); if (isFioRegistered) { diff --git a/lib/entities/parsed_address.dart b/lib/entities/parsed_address.dart index cfd69acbe..eabc606db 100644 --- a/lib/entities/parsed_address.dart +++ b/lib/entities/parsed_address.dart @@ -12,7 +12,8 @@ enum ParseFrom { contact, mastodon, nostr, - thorChain + thorChain, + wellKnown } class ParsedAddress { @@ -142,6 +143,14 @@ class ParsedAddress { ); } + factory ParsedAddress.fetchWellKnownAddress({required String address, required String name}) { + return ParsedAddress( + addresses: [address], + name: name, + parseFrom: ParseFrom.wellKnown, + ); + } + final List<String> addresses; final String name; final String description; diff --git a/lib/entities/preferences_key.dart b/lib/entities/preferences_key.dart index 58a540278..4955690e2 100644 --- a/lib/entities/preferences_key.dart +++ b/lib/entities/preferences_key.dart @@ -76,6 +76,7 @@ class PreferencesKey { static const lookupsUnstoppableDomains = 'looks_up_unstoppable_domain'; static const lookupsOpenAlias = 'looks_up_open_alias'; static const lookupsENS = 'looks_up_ens'; + static const lookupsWellKnown = 'looks_up_well_known'; static const showCameraConsent = 'show_camera_consent'; static String moneroWalletUpdateV1Key(String name) => diff --git a/lib/entities/wellknown_record.dart b/lib/entities/wellknown_record.dart new file mode 100644 index 000000000..edc972f76 --- /dev/null +++ b/lib/entities/wellknown_record.dart @@ -0,0 +1,92 @@ +import 'dart:convert'; + +import 'package:cw_core/crypto_currency.dart'; +import 'package:cw_core/utils/print_verbose.dart'; +import 'package:http/http.dart' as http; + +class WellKnownRecord { + WellKnownRecord({ + required this.address, + required this.name, + }); + + final String name; + final String address; + + static Future<String?> checkWellKnownUsername(String username, CryptoCurrency currency) async { + String jsonLocation = ""; + switch (currency) { + case CryptoCurrency.nano: + jsonLocation = "nano-currency"; + break; + // TODO: add other currencies + default: + return null; + } + + // split the string by the @ symbol: + try { + final List<String> splitStrs = username.split("@"); + String name = splitStrs.first.toLowerCase(); + final String domain = splitStrs.last; + + if (splitStrs.length == 3) { + // for username like @alice@domain.org instead of alice@domain.org + name = splitStrs[1]; + } + + if (name.isEmpty) { + name = "_"; + } + + // lookup domain/.well-known/nano-currency.json and check if it has a nano address: + final http.Response response = await http.get( + Uri.parse("https://$domain/.well-known/$jsonLocation.json?names=$name"), + headers: <String, String>{"Accept": "application/json"}, + ); + + if (response.statusCode != 200) { + return null; + } + final Map<String, dynamic> decoded = json.decode(response.body) as Map<String, dynamic>; + + // Access the first element in the names array and retrieve its address + final List<dynamic> names = decoded["names"] as List<dynamic>; + for (final dynamic item in names) { + if (item["name"].toLowerCase() == name) { + return item["address"] as String; + } + } + } catch (e) { + printV("error checking well-known username: $e"); + } + return null; + } + + static String formatDomainName(String name) { + String formattedName = name; + + if (name.contains("@")) { + formattedName = name.replaceAll("@", "."); + } + + return formattedName; + } + + static Future<WellKnownRecord?> fetchAddressAndName({ + required String formattedName, + required CryptoCurrency currency, + }) async { + String name = formattedName; + + print("formattedName: $formattedName"); + + final address = await checkWellKnownUsername(formattedName, currency); + + if (address == null) { + return null; + } + + return WellKnownRecord(address: address, name: name); + } +} diff --git a/lib/src/screens/send/widgets/extract_address_from_parsed.dart b/lib/src/screens/send/widgets/extract_address_from_parsed.dart index 9ce3ca2b1..106be97ee 100644 --- a/lib/src/screens/send/widgets/extract_address_from_parsed.dart +++ b/lib/src/screens/send/widgets/extract_address_from_parsed.dart @@ -30,6 +30,11 @@ Future<String> extractAddressFromParsed( content = S.of(context).extracted_address_content('${parsedAddress.name} (OpenAlias)'); address = parsedAddress.addresses.first; break; + case ParseFrom.wellKnown: + title = S.of(context).address_detected; + content = S.of(context).extracted_address_content('${parsedAddress.name} (Well-Known)'); + address = parsedAddress.addresses.first; + break; case ParseFrom.fio: title = S.of(context).address_detected; content = S.of(context).extracted_address_content('${parsedAddress.name} (FIO)'); diff --git a/lib/src/screens/settings/domain_lookups_page.dart b/lib/src/screens/settings/domain_lookups_page.dart index aa7e68cd0..0eb559817 100644 --- a/lib/src/screens/settings/domain_lookups_page.dart +++ b/lib/src/screens/settings/domain_lookups_page.dart @@ -45,6 +45,10 @@ class DomainLookupsPage extends BasePage { title: 'Ethereum Name Service', value: _privacySettingsViewModel.looksUpENS, onValueChange: (_, bool value) => _privacySettingsViewModel.setLookupsENS(value)), + SettingsSwitcherCell( + title: '.well-known', + value: _privacySettingsViewModel.looksUpWellKnown, + onValueChange: (_, bool value) => _privacySettingsViewModel.setLookupsWellKnown(value)), //if (!isHaven) it does not work correctly ], diff --git a/lib/store/settings_store.dart b/lib/store/settings_store.dart index aa7df4ba9..318be637e 100644 --- a/lib/store/settings_store.dart +++ b/lib/store/settings_store.dart @@ -115,6 +115,7 @@ abstract class SettingsStoreBase with Store { required this.lookupsUnstoppableDomains, required this.lookupsOpenAlias, required this.lookupsENS, + required this.lookupsWellKnown, required this.customBitcoinFeeRate, required this.silentPaymentsCardDisplay, required this.silentPaymentsAlwaysScan, @@ -459,6 +460,11 @@ abstract class SettingsStoreBase with Store { reaction((_) => lookupsENS, (bool looksUpENS) => _sharedPreferences.setBool(PreferencesKey.lookupsENS, looksUpENS)); + reaction( + (_) => lookupsWellKnown, + (bool looksUpWellKnown) => + _sharedPreferences.setBool(PreferencesKey.lookupsWellKnown, looksUpWellKnown)); + // secure storage keys: reaction( (_) => allowBiometricalAuthentication, @@ -772,6 +778,8 @@ abstract class SettingsStoreBase with Store { @observable bool lookupsENS; + @observable + bool lookupsWellKnown; @observable SyncMode currentSyncMode; @@ -967,6 +975,7 @@ abstract class SettingsStoreBase with Store { sharedPreferences.getBool(PreferencesKey.lookupsUnstoppableDomains) ?? true; final lookupsOpenAlias = sharedPreferences.getBool(PreferencesKey.lookupsOpenAlias) ?? true; final lookupsENS = sharedPreferences.getBool(PreferencesKey.lookupsENS) ?? true; + final lookupsWellKnown = sharedPreferences.getBool(PreferencesKey.lookupsWellKnown) ?? true; final customBitcoinFeeRate = sharedPreferences.getInt(PreferencesKey.customBitcoinFeeRate) ?? 1; final silentPaymentsCardDisplay = sharedPreferences.getBool(PreferencesKey.silentPaymentsCardDisplay) ?? true; @@ -1245,6 +1254,7 @@ abstract class SettingsStoreBase with Store { lookupsUnstoppableDomains: lookupsUnstoppableDomains, lookupsOpenAlias: lookupsOpenAlias, lookupsENS: lookupsENS, + lookupsWellKnown: lookupsWellKnown, customBitcoinFeeRate: customBitcoinFeeRate, silentPaymentsCardDisplay: silentPaymentsCardDisplay, silentPaymentsAlwaysScan: silentPaymentsAlwaysScan, @@ -1414,6 +1424,7 @@ abstract class SettingsStoreBase with Store { sharedPreferences.getBool(PreferencesKey.lookupsUnstoppableDomains) ?? true; lookupsOpenAlias = sharedPreferences.getBool(PreferencesKey.lookupsOpenAlias) ?? true; lookupsENS = sharedPreferences.getBool(PreferencesKey.lookupsENS) ?? true; + lookupsWellKnown = sharedPreferences.getBool(PreferencesKey.lookupsWellKnown) ?? true; customBitcoinFeeRate = sharedPreferences.getInt(PreferencesKey.customBitcoinFeeRate) ?? 1; silentPaymentsCardDisplay = sharedPreferences.getBool(PreferencesKey.silentPaymentsCardDisplay) ?? true; diff --git a/lib/view_model/settings/privacy_settings_view_model.dart b/lib/view_model/settings/privacy_settings_view_model.dart index eaa9f9e84..67f0d88a0 100644 --- a/lib/view_model/settings/privacy_settings_view_model.dart +++ b/lib/view_model/settings/privacy_settings_view_model.dart @@ -94,6 +94,9 @@ abstract class PrivacySettingsViewModelBase with Store { @computed bool get looksUpENS => _settingsStore.lookupsENS; + @computed + bool get looksUpWellKnown => _settingsStore.lookupsWellKnown; + bool get canUseEtherscan => _wallet.type == WalletType.ethereum; bool get canUsePolygonScan => _wallet.type == WalletType.polygon; @@ -130,6 +133,9 @@ abstract class PrivacySettingsViewModelBase with Store { @action void setLookupsENS(bool value) => _settingsStore.lookupsENS = value; + @action + void setLookupsWellKnown(bool value) => _settingsStore.lookupsWellKnown = value; + @action void setLookupsYatService(bool value) => _settingsStore.lookupsYatService = value; From c66a93580a1e32590adb8d6e6c91f8fa4b704a5b Mon Sep 17 00:00:00 2001 From: Omar Hatem <omarh.ismail1@gmail.com> Date: Thu, 16 Jan 2025 00:21:54 +0200 Subject: [PATCH 12/16] Update wellknown_record.dart [skip ci] --- lib/entities/wellknown_record.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/entities/wellknown_record.dart b/lib/entities/wellknown_record.dart index edc972f76..dbe808281 100644 --- a/lib/entities/wellknown_record.dart +++ b/lib/entities/wellknown_record.dart @@ -79,7 +79,7 @@ class WellKnownRecord { }) async { String name = formattedName; - print("formattedName: $formattedName"); + printV("formattedName: $formattedName"); final address = await checkWellKnownUsername(formattedName, currency); From 24c96edc854c612e99ab64911f1e7e48f13c8cd4 Mon Sep 17 00:00:00 2001 From: OmarHatem <omarh.ismail1@gmail.com> Date: Thu, 16 Jan 2025 19:46:53 +0200 Subject: [PATCH 13/16] unfocus fields when tapping exchange [skip ci] --- lib/src/screens/exchange/exchange_page.dart | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/src/screens/exchange/exchange_page.dart b/lib/src/screens/exchange/exchange_page.dart index 2f8e3eb5c..4fb2a2c87 100644 --- a/lib/src/screens/exchange/exchange_page.dart +++ b/lib/src/screens/exchange/exchange_page.dart @@ -231,6 +231,8 @@ class ExchangePage extends BasePage { key: ValueKey('exchange_page_exchange_button_key'), text: S.of(context).exchange, onPressed: () { + FocusScope.of(context).unfocus(); + if (_formKey.currentState != null && _formKey.currentState!.validate()) { if ((exchangeViewModel.depositCurrency == CryptoCurrency.xmr) && From 2fb07dd5d491bb9a220141420fa8ecb8eee2edbc Mon Sep 17 00:00:00 2001 From: OmarHatem <omarh.ismail1@gmail.com> Date: Fri, 17 Jan 2025 16:31:57 +0200 Subject: [PATCH 14/16] unfocus fields when tapping button Minor cleanup [skip ci] --- cw_monero/lib/monero_transaction_info.dart | 25 ---------------------- lib/src/widgets/primary_button.dart | 5 ++++- 2 files changed, 4 insertions(+), 26 deletions(-) diff --git a/cw_monero/lib/monero_transaction_info.dart b/cw_monero/lib/monero_transaction_info.dart index 76064ad11..0ac48dcba 100644 --- a/cw_monero/lib/monero_transaction_info.dart +++ b/cw_monero/lib/monero_transaction_info.dart @@ -1,9 +1,7 @@ import 'package:cw_core/transaction_info.dart'; import 'package:cw_core/monero_amount_format.dart'; -import 'package:cw_core/parseBoolFromString.dart'; import 'package:cw_core/transaction_direction.dart'; import 'package:cw_core/format_amount.dart'; -import 'package:cw_monero/api/transaction_history.dart'; class MoneroTransactionInfo extends TransactionInfo { MoneroTransactionInfo(this.txHash, this.height, this.direction, this.date, @@ -11,29 +9,6 @@ class MoneroTransactionInfo extends TransactionInfo { this.confirmations) : id = "${txHash}_${amount}_${accountIndex}_${addressIndex}"; - MoneroTransactionInfo.fromMap(Map<String, Object?> map) - : id = "${map['hash']}_${map['amount']}_${map['accountIndex']}_${map['addressIndex']}", - txHash = map['hash'] as String, - height = (map['height'] ?? 0) as int, - direction = map['direction'] != null - ? parseTransactionDirectionFromNumber(map['direction'] as String) - : TransactionDirection.incoming, - date = DateTime.fromMillisecondsSinceEpoch( - (int.tryParse(map['timestamp'] as String? ?? '') ?? 0) * 1000), - isPending = parseBoolFromString(map['isPending'] as String), - amount = map['amount'] as int, - accountIndex = int.parse(map['accountIndex'] as String), - addressIndex = map['addressIndex'] as int, - confirmations = map['confirmations'] as int, - key = getTxKey((map['hash'] ?? '') as String), - fee = map['fee'] as int? ?? 0 { - additionalInfo = <String, dynamic>{ - 'key': key, - 'accountIndex': accountIndex, - 'addressIndex': addressIndex - }; - } - final String id; final String txHash; final int height; diff --git a/lib/src/widgets/primary_button.dart b/lib/src/widgets/primary_button.dart index 06bfda157..d5800aa5b 100644 --- a/lib/src/widgets/primary_button.dart +++ b/lib/src/widgets/primary_button.dart @@ -91,7 +91,10 @@ class LoadingPrimaryButton extends StatelessWidget { width: double.infinity, height: 52.0, child: TextButton( - onPressed: (isLoading || isDisabled) ? null : onPressed, + onPressed: (isLoading || isDisabled) ? null : () { + FocusScope.of(context).unfocus(); + onPressed.call(); + }, style: ButtonStyle( backgroundColor: MaterialStateProperty.all(isDisabled ? color.withOpacity(0.5) : color), From aef71d16f145652febfbf16224e2142ea48d8b05 Mon Sep 17 00:00:00 2001 From: cyan <cyjan@mrcyjanek.net> Date: Mon, 20 Jan 2025 16:52:13 +0100 Subject: [PATCH 15/16] CW-860 Fix status for http auth nodes (#1943) --- cw_core/lib/node.dart | 186 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 174 insertions(+), 12 deletions(-) diff --git a/cw_core/lib/node.dart b/cw_core/lib/node.dart index 7d0c2411f..7b3294043 100644 --- a/cw_core/lib/node.dart +++ b/cw_core/lib/node.dart @@ -1,13 +1,18 @@ import 'dart:io'; +import 'dart:math'; import 'package:cw_core/keyable.dart'; +import 'package:cw_core/utils/print_verbose.dart'; import 'dart:convert'; import 'package:http/http.dart' as http; import 'package:hive/hive.dart'; import 'package:cw_core/hive_type_ids.dart'; import 'package:cw_core/wallet_type.dart'; import 'package:http/io_client.dart' as ioc; +import 'dart:math' as math; +import 'package:convert/convert.dart'; +import 'package:crypto/crypto.dart' as crypto; -// import 'package:tor/tor.dart'; +import 'package:crypto/crypto.dart'; part 'node.g.dart'; @@ -170,34 +175,43 @@ class Node extends HiveObject with Keyable { } Future<bool> requestMoneroNode() async { - if (uri.toString().contains(".onion") || useSocksProxy) { + if (useSocksProxy) { return await requestNodeWithProxy(); } + + final path = '/json_rpc'; final rpcUri = isSSL ? Uri.https(uri.authority, path) : Uri.http(uri.authority, path); - final realm = 'monero-rpc'; final body = {'jsonrpc': '2.0', 'id': '0', 'method': 'get_info'}; + try { final authenticatingClient = HttpClient(); - authenticatingClient.badCertificateCallback = ((X509Certificate cert, String host, int port) => true); - authenticatingClient.addCredentials( - rpcUri, - realm, - HttpClientDigestCredentials(login ?? '', password ?? ''), - ); final http.Client client = ioc.IOClient(authenticatingClient); + final jsonBody = json.encode(body); + final response = await client.post( rpcUri, headers: {'Content-Type': 'application/json'}, - body: json.encode(body), + body: jsonBody, ); - client.close(); + // Check if we received a 401 Unauthorized response + if (response.statusCode == 401) { + final daemonRpc = DaemonRpc( + rpcUri.toString(), + username: login??'', + password: password??'', + ); + final response = await daemonRpc.call('get_info', {}); + return !(response['offline'] as bool); + } + + printV("node check response: ${response.body}"); if ((response.body.contains("400 Bad Request") // Some other generic error || @@ -225,7 +239,8 @@ class Node extends HiveObject with Keyable { final resBody = json.decode(response.body) as Map<String, dynamic>; return !(resBody['result']['offline'] as bool); - } catch (_) { + } catch (e) { + printV("error: $e"); return false; } } @@ -316,3 +331,150 @@ class Node extends HiveObject with Keyable { } } } + +/// https://github.com/ManyMath/digest_auth/ +/// HTTP Digest authentication. +/// +/// Adapted from https://github.com/dart-lang/http/issues/605#issue-963962341. +/// +/// Created because http_auth was not working for Monero daemon RPC responses. +class DigestAuth { + final String username; + final String password; + String? realm; + String? nonce; + String? uri; + String? qop = "auth"; + int _nonceCount = 0; + + DigestAuth(this.username, this.password); + + /// Initialize Digest parameters from the `WWW-Authenticate` header. + void initFromAuthorizationHeader(String authInfo) { + final Map<String, String>? values = _splitAuthenticateHeader(authInfo); + if (values != null) { + realm = values['realm']; + // Check if the nonce has changed. + if (nonce != values['nonce']) { + nonce = values['nonce']; + _nonceCount = 0; // Reset nonce count when nonce changes. + } + } + } + + /// Generate the Digest Authorization header. + String getAuthString(String method, String uri) { + this.uri = uri; + _nonceCount++; + String cnonce = _computeCnonce(); + String nc = _formatNonceCount(_nonceCount); + + String ha1 = md5Hash("$username:$realm:$password"); + String ha2 = md5Hash("$method:$uri"); + String response = md5Hash("$ha1:$nonce:$nc:$cnonce:$qop:$ha2"); + + return 'Digest username="$username", realm="$realm", nonce="$nonce", uri="$uri", qop=$qop, nc=$nc, cnonce="$cnonce", response="$response"'; + } + + /// Helper to parse the `WWW-Authenticate` header. + Map<String, String>? _splitAuthenticateHeader(String? header) { + if (header == null || !header.startsWith('Digest ')) { + return null; + } + String token = header.substring(7); // Remove 'Digest '. + final Map<String, String> result = {}; + + final components = token.split(',').map((token) => token.trim()); + for (final component in components) { + final kv = component.split('='); + final key = kv[0]; + final value = kv.sublist(1).join('=').replaceAll('"', ''); + result[key] = value; + } + return result; + } + + /// Helper to compute a random cnonce. + String _computeCnonce() { + final math.Random rnd = math.Random(); + final List<int> values = List<int>.generate(16, (i) => rnd.nextInt(256)); + return hex.encode(values); + } + + /// Helper to format the nonce count. + String _formatNonceCount(int count) => + count.toRadixString(16).padLeft(8, '0'); + + /// Compute the MD5 hash of a string. + String md5Hash(String input) { + return md5.convert(utf8.encode(input)).toString(); + } +} + +class DaemonRpc { + final String rpcUrl; + final String username; + final String password; + + DaemonRpc(this.rpcUrl, {required this.username, required this.password}); + + /// Perform a JSON-RPC call with Digest Authentication. + Future<Map<String, dynamic>> call( + String method, Map<String, dynamic> params) async { + final http.Client client = http.Client(); + final DigestAuth digestAuth = DigestAuth(username, password); + + // Initial request to get the `WWW-Authenticate` header. + final initialResponse = await client.post( + Uri.parse(rpcUrl), + headers: { + 'Content-Type': 'application/json', + }, + body: jsonEncode({ + 'jsonrpc': '2.0', + 'id': '0', + 'method': method, + 'params': params, + }), + ); + + if (initialResponse.statusCode != 401 || + !initialResponse.headers.containsKey('www-authenticate')) { + throw Exception('Unexpected response: ${initialResponse.body}'); + } + + // Extract Digest details from `WWW-Authenticate` header. + final String authInfo = initialResponse.headers['www-authenticate']!; + digestAuth.initFromAuthorizationHeader(authInfo); + + // Create Authorization header for the second request. + String uri = Uri.parse(rpcUrl).path; + String authHeader = digestAuth.getAuthString('POST', uri); + + // Make the authenticated request. + final authenticatedResponse = await client.post( + Uri.parse(rpcUrl), + headers: { + 'Content-Type': 'application/json', + 'Authorization': authHeader, + }, + body: jsonEncode({ + 'jsonrpc': '2.0', + 'id': '0', + 'method': method, + 'params': params, + }), + ); + + if (authenticatedResponse.statusCode != 200) { + throw Exception('RPC call failed: ${authenticatedResponse.body}'); + } + + final Map<String, dynamic> result = jsonDecode(authenticatedResponse.body) as Map<String, dynamic>; + if (result['error'] != null) { + throw Exception('RPC Error: ${result['error']}'); + } + + return result['result'] as Map<String, dynamic>; + } +} \ No newline at end of file From 5b9baf541b13570908e55fe1e05b462adbc7418f Mon Sep 17 00:00:00 2001 From: Serhii <borodenko.sv@gmail.com> Date: Wed, 22 Jan 2025 21:40:06 +0200 Subject: [PATCH 16/16] Cw 903 new screens for new shared seed wallets (#1967) * Update seed verification flow for group wallets * Update res/values/strings_en.arb [skip ci] * Update res/values/strings_ko.arb [skip ci] --------- Co-authored-by: Omar Hatem <omarh.ismail1@gmail.com> --- lib/router.dart | 6 + lib/routes.dart | 1 + .../screens/new_wallet/new_wallet_page.dart | 10 +- .../wallet_group_description_page.dart | 21 +--- .../new_wallet/wallet_group_display_page.dart | 23 +--- ..._group_existing_seed_description_page.dart | 106 ++++++++++++++++++ lib/themes/extensions/theme_type_images.dart | 14 +++ res/values/strings_ar.arb | 3 + res/values/strings_bg.arb | 3 + res/values/strings_cs.arb | 3 + res/values/strings_de.arb | 3 + res/values/strings_en.arb | 3 + res/values/strings_es.arb | 3 + res/values/strings_fr.arb | 3 + res/values/strings_ha.arb | 3 + res/values/strings_hi.arb | 3 + res/values/strings_hr.arb | 3 + res/values/strings_hy.arb | 3 + res/values/strings_id.arb | 3 + res/values/strings_it.arb | 3 + res/values/strings_ja.arb | 3 + res/values/strings_ko.arb | 4 +- res/values/strings_my.arb | 3 + res/values/strings_nl.arb | 3 + res/values/strings_pl.arb | 3 + res/values/strings_pt.arb | 3 + res/values/strings_ru.arb | 3 + res/values/strings_th.arb | 3 + res/values/strings_tl.arb | 3 + res/values/strings_tr.arb | 3 + res/values/strings_uk.arb | 3 + res/values/strings_ur.arb | 3 + res/values/strings_vi.arb | 3 + res/values/strings_yo.arb | 3 + res/values/strings_zh.arb | 3 + 35 files changed, 224 insertions(+), 42 deletions(-) create mode 100644 lib/src/screens/new_wallet/wallet_group_existing_seed_description_page.dart create mode 100644 lib/themes/extensions/theme_type_images.dart diff --git a/lib/router.dart b/lib/router.dart index 315c17178..1c82316e0 100644 --- a/lib/router.dart +++ b/lib/router.dart @@ -50,6 +50,7 @@ import 'package:cake_wallet/src/screens/new_wallet/advanced_privacy_settings_pag import 'package:cake_wallet/src/screens/new_wallet/new_wallet_page.dart'; import 'package:cake_wallet/src/screens/new_wallet/new_wallet_type_page.dart'; import 'package:cake_wallet/src/screens/new_wallet/wallet_group_description_page.dart'; +import 'package:cake_wallet/src/screens/new_wallet/wallet_group_existing_seed_description_page.dart'; import 'package:cake_wallet/src/screens/nodes/node_create_or_edit_page.dart'; import 'package:cake_wallet/src/screens/nodes/pow_node_create_or_edit_page.dart'; import 'package:cake_wallet/src/screens/order_details/order_details_page.dart'; @@ -587,6 +588,11 @@ Route<dynamic> createRoute(RouteSettings settings) { return MaterialPageRoute<void>( builder: (_) => getIt.get<PreSeedPage>(param1: settings.arguments as int)); + case Routes.walletGroupExistingSeedDescriptionPage: + return MaterialPageRoute<void>( + builder: (_) => WalletGroupExistingSeedDescriptionPage( + seedPhraseWordsLength: settings.arguments as int)); + case Routes.transactionSuccessPage: return MaterialPageRoute<void>( builder: (_) => getIt.get<TransactionSuccessPage>(param1: settings.arguments as String)); diff --git a/lib/routes.dart b/lib/routes.dart index 517efca29..4b397c57c 100644 --- a/lib/routes.dart +++ b/lib/routes.dart @@ -116,5 +116,6 @@ class Routes { static const urqrAnimatedPage = '/urqr/animated_page'; static const walletGroupsDisplayPage = '/wallet_groups_display_page'; static const walletGroupDescription = '/wallet_group_description'; + static const walletGroupExistingSeedDescriptionPage = '/wallet_group_existing_seed_description_page'; static const walletSeedVerificationPage = '/wallet_seed_verification_page'; } diff --git a/lib/src/screens/new_wallet/new_wallet_page.dart b/lib/src/screens/new_wallet/new_wallet_page.dart index e2d5a953c..368b3440d 100644 --- a/lib/src/screens/new_wallet/new_wallet_page.dart +++ b/lib/src/screens/new_wallet/new_wallet_page.dart @@ -101,8 +101,14 @@ class _WalletNameFormState extends State<WalletNameForm> { void initState() { _stateReaction ??= reaction((_) => _walletNewVM.state, (ExecutionState state) async { if (state is ExecutedSuccessfullyState) { - Navigator.of(navigatorKey.currentContext ?? context) - .pushNamed(Routes.preSeedPage, arguments: _walletNewVM.seedPhraseWordsLength); + if (widget.isChildWallet) { + Navigator.of(navigatorKey.currentContext ?? context) + .pushNamed(Routes.walletGroupExistingSeedDescriptionPage, + arguments: _walletNewVM.seedPhraseWordsLength); + } else { + Navigator.of(navigatorKey.currentContext ?? context) + .pushNamed(Routes.preSeedPage, arguments: _walletNewVM.seedPhraseWordsLength); + } } if (state is FailureState) { diff --git a/lib/src/screens/new_wallet/wallet_group_description_page.dart b/lib/src/screens/new_wallet/wallet_group_description_page.dart index e892e0d49..b566d0422 100644 --- a/lib/src/screens/new_wallet/wallet_group_description_page.dart +++ b/lib/src/screens/new_wallet/wallet_group_description_page.dart @@ -7,6 +7,7 @@ import 'package:cake_wallet/themes/theme_base.dart'; 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/themes/extensions/theme_type_images.dart'; class WalletGroupDescriptionPage extends BasePage { WalletGroupDescriptionPage({required this.selectedWalletType}); @@ -25,10 +26,7 @@ class WalletGroupDescriptionPage extends BasePage { padding: EdgeInsets.all(24), child: Column( children: [ - Image.asset( - _getThemedWalletGroupImage(currentTheme.type), - height: 200, - ), + Image.asset(currentTheme.type.walletGroupImage, height: 200), SizedBox(height: 32), Expanded( child: Text.rich( @@ -91,19 +89,4 @@ class WalletGroupDescriptionPage extends BasePage { ), ); } - - String _getThemedWalletGroupImage(ThemeType theme) { - final lightImage = 'assets/images/wallet_group_light.png'; - final darkImage = 'assets/images/wallet_group_dark.png'; - final brightImage = 'assets/images/wallet_group_bright.png'; - - switch (theme) { - case ThemeType.bright: - return brightImage; - case ThemeType.light: - return lightImage; - default: - return darkImage; - } - } } diff --git a/lib/src/screens/new_wallet/wallet_group_display_page.dart b/lib/src/screens/new_wallet/wallet_group_display_page.dart index a99d2bac7..549449a68 100644 --- a/lib/src/screens/new_wallet/wallet_group_display_page.dart +++ b/lib/src/screens/new_wallet/wallet_group_display_page.dart @@ -4,12 +4,13 @@ import 'package:cake_wallet/routes.dart'; import 'package:cake_wallet/src/screens/base_page.dart'; import 'package:cake_wallet/src/screens/new_wallet/widgets/grouped_wallet_expansion_tile.dart'; import 'package:cake_wallet/src/widgets/primary_button.dart'; +import 'package:cake_wallet/themes/extensions/cake_text_theme.dart'; +import 'package:cake_wallet/themes/extensions/theme_type_images.dart'; import 'package:cake_wallet/themes/theme_base.dart'; import 'package:cake_wallet/view_model/wallet_groups_display_view_model.dart'; import 'package:cw_core/wallet_type.dart'; import 'package:flutter/material.dart'; import 'package:flutter_mobx/flutter_mobx.dart'; -import '../../../themes/extensions/cake_text_theme.dart'; class WalletGroupsDisplayPage extends BasePage { WalletGroupsDisplayPage(this.walletGroupsDisplayViewModel); @@ -165,10 +166,7 @@ class WalletGroupEmptyStateWidget extends StatelessWidget { Widget build(BuildContext context) { return Column( children: [ - Image.asset( - _getThemedWalletGroupImage(currentTheme.type), - scale: 1.8, - ), + Image.asset(currentTheme.type.walletGroupImage, scale: 1.8), SizedBox(height: 32), Text.rich( TextSpan( @@ -194,19 +192,4 @@ class WalletGroupEmptyStateWidget extends StatelessWidget { ], ); } - - String _getThemedWalletGroupImage(ThemeType theme) { - final lightImage = 'assets/images/wallet_group_light.png'; - final darkImage = 'assets/images/wallet_group_dark.png'; - final brightImage = 'assets/images/wallet_group_bright.png'; - - switch (theme) { - case ThemeType.bright: - return brightImage; - case ThemeType.light: - return lightImage; - default: - return darkImage; - } - } } diff --git a/lib/src/screens/new_wallet/wallet_group_existing_seed_description_page.dart b/lib/src/screens/new_wallet/wallet_group_existing_seed_description_page.dart new file mode 100644 index 000000000..4eab8fcec --- /dev/null +++ b/lib/src/screens/new_wallet/wallet_group_existing_seed_description_page.dart @@ -0,0 +1,106 @@ +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/widgets/primary_button.dart'; +import 'package:cake_wallet/themes/extensions/cake_text_theme.dart'; +import 'package:cake_wallet/themes/extensions/dashboard_page_theme.dart'; +import 'package:cake_wallet/themes/extensions/theme_type_images.dart'; +import 'package:cake_wallet/themes/theme_base.dart'; +import 'package:flutter/material.dart'; + +class WalletGroupExistingSeedDescriptionPage extends BasePage { + WalletGroupExistingSeedDescriptionPage({required this.seedPhraseWordsLength}); + + final int seedPhraseWordsLength; + + @override + String get title => S.current.wallet_group; + + @override + Widget body(BuildContext context) { + final textStyle = TextStyle( + fontSize: 16, + fontWeight: FontWeight.w400, + color: Theme.of(context).extension<CakeTextTheme>()!.secondaryTextColor, + ); + + return Container( + alignment: Alignment.center, + padding: EdgeInsets.all(24), + child: Column( + children: [ + Image.asset(currentTheme.type.walletGroupImage, height: 200), + SizedBox(height: 32), + Expanded( + child: RichText( + text: TextSpan( + children: [ + TextSpan( + text: S.current.wallet_group_description_existing_seed + '\n\n', + style: textStyle), + TextSpan( + text: S.current.wallet_group_description_open_wallet + '\n\n', + style: textStyle), + TextSpan( + text: S.current.wallet_group_description_view_seed + '\n', style: textStyle), + TextSpan( + text: S.current.seed_display_path, + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w800, + color: Theme.of(context).extension<CakeTextTheme>()!.secondaryTextColor, + ), + ), + ], + ), + textAlign: TextAlign.center, + ), + ), + Column( + children: <Widget>[ + Row( + mainAxisSize: MainAxisSize.max, + children: <Widget>[ + Flexible( + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 8.0), + child: PrimaryButton( + key: ValueKey( + 'wallet_group_existing_seed_description_page_verify_seed_button_key'), + onPressed: () => Navigator.pushNamed(context, Routes.preSeedPage, + arguments: seedPhraseWordsLength), + text: S.current.verify_seed, + color: Theme.of(context).cardColor, + textColor: currentTheme.type == ThemeType.dark + ? Theme.of(context).extension<DashboardPageTheme>()!.textColor + : Theme.of(context).extension<CakeTextTheme>()!.buttonTextColor, + ), + ), + ), + Flexible( + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 8.0), + child: Builder( + builder: (context) => PrimaryButton( + key: ValueKey( + 'wallet_group_existing_seed_description_page_open_wallet_button_key'), + onPressed: () { + Navigator.of(context).popUntil((route) => route.isFirst); + }, + text: S.current.open_wallet, + color: Theme.of(context).primaryColor, + textColor: Colors.white, + ), + ), + ), + ) + ], + ), + SizedBox(height: 12), + ], + ) + ], + ), + ); + } +} diff --git a/lib/themes/extensions/theme_type_images.dart b/lib/themes/extensions/theme_type_images.dart new file mode 100644 index 000000000..39461e702 --- /dev/null +++ b/lib/themes/extensions/theme_type_images.dart @@ -0,0 +1,14 @@ +import 'package:cake_wallet/themes/theme_base.dart'; + +extension ThemeTypeImages on ThemeType { + String get walletGroupImage { + switch (this) { + case ThemeType.bright: + return 'assets/images/wallet_group_bright.png'; + case ThemeType.light: + return 'assets/images/wallet_group_light.png'; + default: + return 'assets/images/wallet_group_dark.png'; + } + } +} diff --git a/res/values/strings_ar.arb b/res/values/strings_ar.arb index b0955b6d7..e067eca08 100644 --- a/res/values/strings_ar.arb +++ b/res/values/strings_ar.arb @@ -925,10 +925,13 @@ "waitFewSecondForTxUpdate": "ﺕﻼﻣﺎﻌﻤﻟﺍ ﻞﺠﺳ ﻲﻓ ﺔﻠﻣﺎﻌﻤﻟﺍ ﺲﻜﻌﻨﺗ ﻰﺘﺣ ﻥﺍﻮﺛ ﻊﻀﺒﻟ ﺭﺎﻈﺘﻧﻻﺍ ﻰﺟﺮﻳ", "wallet": "محفظة", "wallet_group": "مجموعة محفظة", + "wallet_group_description_existing_seed": "لقد اخترت استخدام بذرة موجودة لهذه المحفظة. يمكنك التحقق من البذرة مرة أخرى إذا كنت بحاجة إلى تأكيدها أو كتابتها.", "wallet_group_description_four": "لإنشاء محفظة مع بذرة جديدة تماما.", "wallet_group_description_one": "في محفظة الكيك ، يمكنك إنشاء ملف", + "wallet_group_description_open_wallet": "خلاف ذلك ، يمكنك الاستمرار في فتح المحفظة", "wallet_group_description_three": "لرؤية المحافظ المتاحة و/أو شاشة مجموعات المحفظة. أو اختر", "wallet_group_description_two": "عن طريق اختيار محفظة موجودة لتبادل البذور مع. يمكن أن تحتوي كل مجموعة محفظة على محفظة واحدة من كل نوع من العملة. \n\n يمكنك تحديدها", + "wallet_group_description_view_seed": "يمكنك دائمًا عرض هذه البذرة مرة أخرى تحت", "wallet_group_empty_state_text_one": "يبدو أنه ليس لديك أي مجموعات محفظة متوافقة !\n\n انقر", "wallet_group_empty_state_text_two": "أدناه لجعل واحدة جديدة.", "wallet_keys": "سييد المحفظة / المفاتيح", diff --git a/res/values/strings_bg.arb b/res/values/strings_bg.arb index e1fc3bd87..8536200fd 100644 --- a/res/values/strings_bg.arb +++ b/res/values/strings_bg.arb @@ -925,10 +925,13 @@ "waitFewSecondForTxUpdate": "Моля, изчакайте няколко секунди, докато транзакцията се отрази в историята на транзакциите", "wallet": "Портфейл", "wallet_group": "Група на портфейла", + "wallet_group_description_existing_seed": "Вие сте избрали да използвате съществуващо семе за този портфейл. Можете да проверите отново семето, ако трябва да го потвърдите или запишете.", "wallet_group_description_four": "За да създадете портфейл с изцяло ново семе.", "wallet_group_description_one": "В портфейла за торта можете да създадете a", + "wallet_group_description_open_wallet": "В противен случай можете да продължите да отваряте портфейла", "wallet_group_description_three": "За да видите наличния екран за портфейли и/или групи за портфейли. Или изберете", "wallet_group_description_two": "Чрез избора на съществуващ портфейл, с който да споделите семе. Всяка група за портфейл може да съдържа по един портфейл от всеки тип валута. \n\n Можете да изберете", + "wallet_group_description_view_seed": "Винаги можете да видите това семе отново под", "wallet_group_empty_state_text_one": "Изглежда, че нямате съвместими групи портфейли !\n\n tap", "wallet_group_empty_state_text_two": "по -долу, за да се направи нов.", "wallet_keys": "Seed/keys на портфейла", diff --git a/res/values/strings_cs.arb b/res/values/strings_cs.arb index 29c04496d..8ec02ddb0 100644 --- a/res/values/strings_cs.arb +++ b/res/values/strings_cs.arb @@ -925,10 +925,13 @@ "waitFewSecondForTxUpdate": "Počkejte několik sekund, než se transakce projeví v historii transakcí", "wallet": "Peněženka", "wallet_group": "Skupina peněženky", + "wallet_group_description_existing_seed": "Rozhodli jste se použít existující semeno pro tuto peněženku. Semeno můžete znovu ověřit, pokud potřebujete potvrdit nebo zapisovat.", "wallet_group_description_four": "Vytvoření peněženky s zcela novým semenem.", "wallet_group_description_one": "V peněžence dortu můžete vytvořit a", + "wallet_group_description_open_wallet": "Jinak můžete pokračovat v otevírání peněženky", "wallet_group_description_three": "Chcete -li zobrazit dostupnou obrazovku Skupina skupin peněženek a/nebo skupin peněženek. Nebo zvolit", "wallet_group_description_two": "Výběrem existující peněženky pro sdílení semeno. Každá skupina peněženek může obsahovat jednu peněženku každého typu měny. \n\n Můžete si vybrat", + "wallet_group_description_view_seed": "Toto semeno si můžete vždy znovu prohlédnout", "wallet_group_empty_state_text_one": "Vypadá to, že nemáte žádné kompatibilní skupiny peněženky !\n\n", "wallet_group_empty_state_text_two": "Níže vytvořit nový.", "wallet_keys": "Seed/klíče peněženky", diff --git a/res/values/strings_de.arb b/res/values/strings_de.arb index 54c3a70e7..762f93451 100644 --- a/res/values/strings_de.arb +++ b/res/values/strings_de.arb @@ -928,10 +928,13 @@ "waiting_payment_confirmation": "Warte auf Zahlungsbestätigung", "wallet": "Geldbörse", "wallet_group": "Walletgruppe", + "wallet_group_description_existing_seed": "Sie haben für diese Brieftasche einen vorhandenen Samen verwendet. Sie können den Samen erneut überprüfen, wenn Sie ihn bestätigen oder aufschreiben müssen.", "wallet_group_description_four": "eine Wallet mit einem völlig neuen Seed schaffen.", "wallet_group_description_one": "In CakeWallet können Sie eine erstellen", + "wallet_group_description_open_wallet": "Andernfalls können Sie die Brieftasche weiter öffnen", "wallet_group_description_three": "Sehen Sie den Bildschirm zur verfügbaren Wallet und/oder Walletgruppen. Oder wählen", "wallet_group_description_two": "Durch die Auswahl einer vorhandenen Wallet, mit der ein Seed geteilt werden kann. Jede Walletgruppe kann eine einzelne Wallet jedes Währungstyps enthalten. \n\n Sie können auswählen", + "wallet_group_description_view_seed": "Sie können diesen Samen immer wieder untersuchen", "wallet_group_empty_state_text_one": "Sieht so aus, als hätten Sie keine kompatiblen Walletgruppen !\n\n TAP", "wallet_group_empty_state_text_two": "unten, um einen neuen zu machen.", "wallet_keys": "Wallet-Seed/-Schlüssel", diff --git a/res/values/strings_en.arb b/res/values/strings_en.arb index 995fb5595..0495e5d75 100644 --- a/res/values/strings_en.arb +++ b/res/values/strings_en.arb @@ -925,10 +925,13 @@ "waitFewSecondForTxUpdate": "Kindly wait for a few seconds for transaction to reflect in transactions history", "wallet": "Wallet", "wallet_group": "Wallet Group", + "wallet_group_description_existing_seed": "You’ve chosen to use an existing seed for this wallet. You may verify the seed again if you need to confirm or write it down.", "wallet_group_description_four": "to create a wallet with an entirely new seed.", "wallet_group_description_one": "In Cake Wallet, you can create a", + "wallet_group_description_open_wallet": "Otherwise, you can continue to open the wallet", "wallet_group_description_three": "to see the available wallets and/or wallet groups screen. Or choose", "wallet_group_description_two": "by selecting an existing wallet to share a seed with. Each wallet group can contain a single wallet of each currency type.\n\nYou can select", + "wallet_group_description_view_seed": "You can always view this seed again under", "wallet_group_empty_state_text_one": "Looks like you don't have any compatible wallet groups!\n\nTap", "wallet_group_empty_state_text_two": "below to make a new one.", "wallet_keys": "Wallet seed/keys", diff --git a/res/values/strings_es.arb b/res/values/strings_es.arb index 011206fbf..7084894eb 100644 --- a/res/values/strings_es.arb +++ b/res/values/strings_es.arb @@ -926,10 +926,13 @@ "waitFewSecondForTxUpdate": "Espera unos segundos para que la transacción se refleje en el historial de transacciones.", "wallet": "Billetera", "wallet_group": "Grupo de billetera", + "wallet_group_description_existing_seed": "Ha elegido usar una semilla existente para esta billetera. Puede verificar la semilla nuevamente si necesita confirmarla o escribirla.", "wallet_group_description_four": "Para crear una billetera con una semilla completamente nueva.", "wallet_group_description_one": "En la billetera de pastel, puedes crear un", + "wallet_group_description_open_wallet": "De lo contrario, puede continuar abriendo la billetera", "wallet_group_description_three": "Para ver las billeteras disponibles y/o la pantalla de grupos de billeteras. O elegir", "wallet_group_description_two": "Seleccionando una billetera existente para compartir una semilla con. Cada grupo de billetera puede contener una sola billetera de cada tipo de moneda. \n\n puedes seleccionar", + "wallet_group_description_view_seed": "Siempre puedes ver esta semilla nuevamente debajo", "wallet_group_empty_state_text_one": "Parece que no tienes ningún grupo de billetera compatible !\n\n toque", "wallet_group_empty_state_text_two": "a continuación para hacer uno nuevo.", "wallet_keys": "Billetera semilla/claves", diff --git a/res/values/strings_fr.arb b/res/values/strings_fr.arb index 7e2907c8f..4e3f20200 100644 --- a/res/values/strings_fr.arb +++ b/res/values/strings_fr.arb @@ -925,10 +925,13 @@ "waitFewSecondForTxUpdate": "Veuillez attendre quelques secondes pour que la transaction soit reflétée dans l'historique des transactions.", "wallet": "Portefeuille", "wallet_group": "Groupe de portefeuille", + "wallet_group_description_existing_seed": "Vous avez choisi d'utiliser une graine existante pour ce portefeuille. Vous pouvez vérifier à nouveau la graine si vous avez besoin de le confirmer ou de le noter.", "wallet_group_description_four": "Pour créer un portefeuille avec une graine entièrement nouvelle.", "wallet_group_description_one": "Dans Cake Wallet, vous pouvez créer un", + "wallet_group_description_open_wallet": "Sinon, vous pouvez continuer à ouvrir le portefeuille", "wallet_group_description_three": "Pour voir les portefeuilles et / ou les groupes de portefeuilles disponibles. Ou choisir", "wallet_group_description_two": "En sélectionnant un portefeuille existant pour partager une graine avec. Chaque groupe de portefeuille peut contenir un seul portefeuille de chaque type de devise. \n\n Vous pouvez sélectionner", + "wallet_group_description_view_seed": "Vous pouvez toujours revoir cette graine sous", "wallet_group_empty_state_text_one": "On dirait que vous n'avez pas de groupes de portefeuilles compatibles !\n\n Tap", "wallet_group_empty_state_text_two": "Ci-dessous pour en faire un nouveau.", "wallet_keys": "Phrase secrète (seed)/Clefs du portefeuille (wallet)", diff --git a/res/values/strings_ha.arb b/res/values/strings_ha.arb index d06210e3d..b37a88b61 100644 --- a/res/values/strings_ha.arb +++ b/res/values/strings_ha.arb @@ -927,10 +927,13 @@ "waitFewSecondForTxUpdate": "Da fatan za a jira ƴan daƙiƙa don ciniki don yin tunani a tarihin ma'amala", "wallet": "Zabira", "wallet_group": "Wallet kungiyar", + "wallet_group_description_existing_seed": "Kun zaɓi yin amfani da iri ɗaya na data kasance don wannan Wallet.you na iya tabbatar da zuriyar kuma idan kuna buƙatar tabbatarwa ko rubuta shi.", "wallet_group_description_four": "Don ƙirƙirar walat tare da sabon iri.", "wallet_group_description_one": "A cikin walat walat, zaka iya ƙirƙirar", + "wallet_group_description_open_wallet": "In ba haka ba, zaku iya ci gaba da buɗe walat ɗin", "wallet_group_description_three": "Don ganin wallets da / ko allon walat din. Ko zabi", "wallet_group_description_two": "ta hanyar zabar walat mai gudana don raba iri tare da. Kowane rukunin walat na iya ƙunsar watsarin kowane nau'in kuɗi. \n\n Zaka iya zaɓar", + "wallet_group_description_view_seed": "Koyaushe zaka iya duba wannan zuriya", "wallet_group_empty_state_text_one": "Kamar dai ba ku da wata ƙungiya matattara !\n\n Taɓa", "wallet_group_empty_state_text_two": "da ke ƙasa don yin sabo.", "wallet_keys": "Iri/maɓalli na walat", diff --git a/res/values/strings_hi.arb b/res/values/strings_hi.arb index 74de1126e..1f8fd30eb 100644 --- a/res/values/strings_hi.arb +++ b/res/values/strings_hi.arb @@ -927,10 +927,13 @@ "waitFewSecondForTxUpdate": "लेन-देन इतिहास में लेन-देन प्रतिबिंबित होने के लिए कृपया कुछ सेकंड प्रतीक्षा करें", "wallet": "बटुआ", "wallet_group": "बटुए समूह", + "wallet_group_description_existing_seed": "आपने इस वॉलेट के लिए एक मौजूदा बीज का उपयोग करने के लिए चुना है। यदि आपको इसकी पुष्टि करने या लिखने की आवश्यकता है, तो आप फिर से बीज को सत्यापित कर सकते हैं।", "wallet_group_description_four": "एक पूरी तरह से नए बीज के साथ एक बटुआ बनाने के लिए।", "wallet_group_description_one": "केक बटुए में, आप एक बना सकते हैं", + "wallet_group_description_open_wallet": "अन्यथा, आप बटुए खोलना जारी रख सकते हैं", "wallet_group_description_three": "उपलब्ध वॉलेट और/या वॉलेट समूह स्क्रीन देखने के लिए। या चुनें", "wallet_group_description_two": "एक बीज साझा करने के लिए एक मौजूदा बटुए का चयन करके। प्रत्येक वॉलेट समूह में प्रत्येक मुद्रा प्रकार का एक एकल वॉलेट हो सकता है।\n\nआप चयन कर सकते हैं", + "wallet_group_description_view_seed": "आप हमेशा इस बीज को फिर से देख सकते हैं", "wallet_group_empty_state_text_one": "लगता है कि आपके पास कोई संगत बटुआ समूह नहीं है!\n\nनल", "wallet_group_empty_state_text_two": "नीचे एक नया बनाने के लिए।", "wallet_keys": "बटुआ बीज / चाबियाँ", diff --git a/res/values/strings_hr.arb b/res/values/strings_hr.arb index 41768bd4f..0cb5988c8 100644 --- a/res/values/strings_hr.arb +++ b/res/values/strings_hr.arb @@ -925,10 +925,13 @@ "waitFewSecondForTxUpdate": "Pričekajte nekoliko sekundi da se transakcija prikaže u povijesti transakcija", "wallet": "Novčanik", "wallet_group": "Skupina novčanika", + "wallet_group_description_existing_seed": "Odlučili ste koristiti postojeće sjeme za ovaj novčanik. Možete ponovno provjeriti sjeme ako ga trebate potvrditi ili zapisati.", "wallet_group_description_four": "Da biste stvorili novčanik s potpuno novim sjemenom.", "wallet_group_description_one": "U novčaniku kolača možete stvoriti a", + "wallet_group_description_open_wallet": "Inače možete nastaviti otvarati novčanik", "wallet_group_description_three": "Da biste vidjeli zaslon dostupnih novčanika i/ili grupa novčanika. Ili odaberite", "wallet_group_description_two": "Odabirom postojećeg novčanika s kojim ćete dijeliti sjeme. Svaka grupa novčanika može sadržavati jedan novčanik svake vrste valute. \n\n", + "wallet_group_description_view_seed": "Uvijek možete ponovo pogledati ovo sjeme ispod", "wallet_group_empty_state_text_one": "Izgleda da nemate nikakve kompatibilne grupe novčanika !\n\n", "wallet_group_empty_state_text_two": "Ispod da napravite novi.", "wallet_keys": "Pristupni izraz/ključ novčanika", diff --git a/res/values/strings_hy.arb b/res/values/strings_hy.arb index 2a3aeed6d..eaf413027 100644 --- a/res/values/strings_hy.arb +++ b/res/values/strings_hy.arb @@ -925,10 +925,13 @@ "waitFewSecondForTxUpdate": "Խնդրում ենք սպասել մի քանի վայրկյան, որպեսզի գործարքը արտացոլվի գործարքների պատմության մեջ", "wallet": "Դրամապանակ", "wallet_group": "Դրամապանակների խումբ", + "wallet_group_description_existing_seed": "Դուք ընտրել եք օգտագործել այս դրամապանակի համար գոյություն ունեցող սերմը: Կարող եք կրկին հաստատել սերմը, եթե անհրաժեշտ է հաստատել կամ գրել այն:", "wallet_group_description_four": "Ամբողջովին նոր սերմով դրամապանակ ստեղծելու համար:", "wallet_group_description_one": "Տորթի դրամապանակում կարող եք ստեղծել ա", + "wallet_group_description_open_wallet": "Հակառակ դեպքում, դուք կարող եք շարունակել բացել դրամապանակը", "wallet_group_description_three": "Տեսնել առկա դրամապանակներն ու (կամ) դրամապանակների խմբերի էկրանը: Կամ ընտրել", "wallet_group_description_two": "ընտրելով գոյություն ունեցող դրամապանակ `սերմը կիսելու համար: Դրամապանակների յուրաքանչյուր խումբ կարող է պարունակել յուրաքանչյուր արժույթի տեսակի մեկ դրամապանակ:\n\nԿարող եք ընտրել", + "wallet_group_description_view_seed": "Միշտ կարող եք կրկին դիտել այս սերմը ներքեւում", "wallet_group_empty_state_text_one": "Կարծես թե որեւէ համատեղելի դրամապանակի խմբեր չունեք:\n\nԹակել", "wallet_group_empty_state_text_two": "ներքեւում `նորը կազմելու համար:", "wallet_keys": "Դրամապանակի սերմ/բանալիներ", diff --git a/res/values/strings_id.arb b/res/values/strings_id.arb index 90bf4d806..f53bd2963 100644 --- a/res/values/strings_id.arb +++ b/res/values/strings_id.arb @@ -928,10 +928,13 @@ "waitFewSecondForTxUpdate": "Mohon tunggu beberapa detik hingga transaksi terlihat di riwayat transaksi", "wallet": "Dompet", "wallet_group": "Kelompok dompet", + "wallet_group_description_existing_seed": "Anda telah memilih untuk menggunakan benih yang ada untuk dompet ini. Anda dapat memverifikasi benih lagi jika Anda perlu mengonfirmasi atau menuliskannya.", "wallet_group_description_four": "Untuk membuat dompet dengan benih yang sama sekali baru.", "wallet_group_description_one": "Di dompet kue, Anda dapat membuat file", + "wallet_group_description_open_wallet": "Jika tidak, Anda dapat terus membuka dompet", "wallet_group_description_three": "Untuk melihat layar dompet dan/atau grup dompet yang tersedia. Atau pilih", "wallet_group_description_two": "dengan memilih dompet yang ada untuk berbagi benih dengan. Setiap grup dompet dapat berisi satu dompet dari setiap jenis mata uang. \n\n Anda dapat memilih", + "wallet_group_description_view_seed": "Anda selalu dapat melihat benih ini lagi di bawah", "wallet_group_empty_state_text_one": "Sepertinya Anda tidak memiliki grup dompet yang kompatibel !\n\n tap", "wallet_group_empty_state_text_two": "di bawah ini untuk membuat yang baru.", "wallet_keys": "Seed/kunci dompet", diff --git a/res/values/strings_it.arb b/res/values/strings_it.arb index c3796be5a..5eaa2e58e 100644 --- a/res/values/strings_it.arb +++ b/res/values/strings_it.arb @@ -928,10 +928,13 @@ "waiting_payment_confirmation": "In attesa di conferma del pagamento", "wallet": "Portafoglio", "wallet_group": "Gruppo di portafoglio", + "wallet_group_description_existing_seed": "Hai scelto di utilizzare un seme esistente per questo portafoglio. Puoi verificare di nuovo il seme se devi confermarlo o scriverlo.", "wallet_group_description_four": "Per creare un portafoglio con un seme completamente nuovo.", "wallet_group_description_one": "Nel portafoglio di torte, puoi creare un", + "wallet_group_description_open_wallet": "Altrimenti, puoi continuare ad aprire il portafoglio", "wallet_group_description_three": "Per vedere la schermata di portafogli e/o gruppi di portafogli disponibili. O scegli", "wallet_group_description_two": "Selezionando un portafoglio esistente con cui condividere un seme. Ogni gruppo di portafoglio può contenere un singolo portafoglio di ciascun tipo di valuta. \n\n È possibile selezionare", + "wallet_group_description_view_seed": "Puoi sempre visualizzare di nuovo questo seme sotto", "wallet_group_empty_state_text_one": "Sembra che tu non abbia alcun gruppo di portafoglio compatibile !\n\n TAP", "wallet_group_empty_state_text_two": "Di seguito per crearne uno nuovo.", "wallet_keys": "Seme Portafoglio /chiavi", diff --git a/res/values/strings_ja.arb b/res/values/strings_ja.arb index 4ccd2d830..4427f7d7b 100644 --- a/res/values/strings_ja.arb +++ b/res/values/strings_ja.arb @@ -926,10 +926,13 @@ "waitFewSecondForTxUpdate": "取引履歴に取引が反映されるまで数秒お待ちください。", "wallet": "財布", "wallet_group": "ウォレットグループ", + "wallet_group_description_existing_seed": "この財布に既存の種子を使用することを選択しました。確認または書き留める必要がある場合は、シードをもう一度確認できます。", "wallet_group_description_four": "まったく新しい種子の財布を作成します。", "wallet_group_description_one": "ケーキウォレットでは、aを作成できます", + "wallet_group_description_open_wallet": "それ以外の場合は、ウォレットを開き続けることができます", "wallet_group_description_three": "利用可能なウォレットおよび/またはウォレットグループの画面を表示します。または選択します", "wallet_group_description_two": "既存のウォレットを選択して種子を共有します。各ウォレットグループには、各通貨タイプの単一のウォレットを含めることができます。\n\n選択できます", + "wallet_group_description_view_seed": "いつでもこの種を再び見ることができます", "wallet_group_empty_state_text_one": "互換性のあるウォレットグループがないようです!\n\nタップ", "wallet_group_empty_state_text_two": "以下に新しいものを作るために。", "wallet_keys": "ウォレットシード/キー", diff --git a/res/values/strings_ko.arb b/res/values/strings_ko.arb index 67a69e26b..e84d713cc 100644 --- a/res/values/strings_ko.arb +++ b/res/values/strings_ko.arb @@ -512,7 +512,6 @@ "please_fill_totp": "다른 기기에 있는 8자리 코드를 입력하세요.", "please_make_selection": "아래에서 선택하십시오 지갑 만들기 또는 복구.", "please_reference_document": "자세한 내용은 아래 문서를 참조하십시오.", - "Please_reference_document": "자세한 내용은 아래 문서를 참조하십시오.", "please_select": "선택 해주세요:", "please_select_backup_file": "백업 파일을 선택하고 백업 암호를 입력하십시오.", "please_try_to_connect_to_another_node": "다른 노드에 연결을 시도하십시오", @@ -926,10 +925,13 @@ "waitFewSecondForTxUpdate": "거래 내역에 거래가 반영될 때까지 몇 초 정도 기다려 주세요.", "wallet": "지갑", "wallet_group": "지갑 그룹", + "wallet_group_description_existing_seed": "이 지갑에 기존 씨앗을 사용하기로 선택했습니다. 확인하거나 작성 해야하는 경우 씨앗을 다시 확인할 수 있습니다.", "wallet_group_description_four": "완전히 새로운 씨앗으로 지갑을 만듭니다.", "wallet_group_description_one": "케이크 지갑에서는 a를 만들 수 있습니다", + "wallet_group_description_open_wallet": "그렇지 않으면 지갑을 계속 열 수 있습니다", "wallet_group_description_three": "사용 가능한 지갑 및/또는 지갑 그룹 스크린을 볼 수 있습니다. 또는 선택하십시오", "wallet_group_description_two": "씨앗을 공유 할 기존 지갑을 선택함으로써. 각 지갑 그룹은 각 통화 유형의 단일 지갑을 포함 할 수 있습니다. \n\n", + "wallet_group_description_view_seed": "이 씨앗을 언제든지 다시 볼 수 있습니다", "wallet_group_empty_state_text_one": "호환 지갑 그룹이없는 것 같습니다 !\n\n TAP", "wallet_group_empty_state_text_two": "아래에서 새로운 것을 만들기 위해.", "wallet_keys": "지갑 시드 / 키", diff --git a/res/values/strings_my.arb b/res/values/strings_my.arb index dd2909d3f..e25956a4c 100644 --- a/res/values/strings_my.arb +++ b/res/values/strings_my.arb @@ -925,10 +925,13 @@ "waitFewSecondForTxUpdate": "ငွေပေးငွေယူ မှတ်တမ်းတွင် ရောင်ပြန်ဟပ်ရန် စက္ကန့်အနည်းငယ်စောင့်ပါ။", "wallet": "ပိုက်ဆံအိတ်", "wallet_group": "ပိုက်ဆံအိတ်အုပ်စု", + "wallet_group_description_existing_seed": "ဒီပိုက်ဆံအိတ်အတွက်ရှိပြီးသားမျိုးစေ့ကိုသုံးဖို့သင်ရွေးချယ်ခဲ့တယ်။ သင်ကအတည်ပြုရန်သို့မဟုတ်ရေးရန်လိုအပ်လျှင်မျိုးစေ့ကိုထပ်မံအတည်ပြုနိုင်သည်။", "wallet_group_description_four": "လုံးဝအသစ်သောမျိုးစေ့နှင့်အတူပိုက်ဆံအိတ်ဖန်တီးရန်။", "wallet_group_description_one": "ကိတ်မုန့်၌, သင်တစ် ဦး ဖန်တီးနိုင်ပါတယ်", + "wallet_group_description_open_wallet": "ဒီလိုမှမဟုတ်ရင်သင်ပိုက်ဆံအိတ်ကိုဆက်ဖွင့်နိုင်တယ်", "wallet_group_description_three": "ရရှိနိုင်သည့်ပိုက်ဆံအိတ်နှင့် / သို့မဟုတ်ပိုက်ဆံအိတ်အုပ်စုများမြင်ကွင်းကိုကြည့်ရှုရန်။ သို့မဟုတ်ရွေးချယ်ပါ", "wallet_group_description_two": "နှင့်အတူမျိုးစေ့ဝေမျှဖို့ရှိပြီးသားပိုက်ဆံအိတ်တစ်ခုရွေးချယ်ခြင်းအားဖြင့်။ ပိုက်ဆံအိတ်အုပ်စုတစ်ခုစီတွင်ငွေကြေးအမျိုးအစားတစ်ခုစီ၏တစ်ခုတည်းသောပိုက်ဆံအိတ်တစ်ခုပါ 0 င်နိုင်သည်။ \n\n သင်ရွေးချယ်နိုင်သည်", + "wallet_group_description_view_seed": "သင်သည်ဤမျိုးစေ့ကိုနောက်တဖန်ရှုမြင်နိုင်သည်", "wallet_group_empty_state_text_one": "သင့်တွင်သဟဇာတဖြစ်သောပိုက်ဆံအိတ်အုပ်စုများမရှိပါ။ !\n\n ကိုအသာပုတ်ပါ", "wallet_group_empty_state_text_two": "အသစ်တစ်ခုကိုတစ်ခုလုပ်ဖို့အောက်တွင်ဖော်ပြထားသော။", "wallet_keys": "ပိုက်ဆံအိတ် အစေ့/သော့များ", diff --git a/res/values/strings_nl.arb b/res/values/strings_nl.arb index 8b32d669f..cc5bb5ef6 100644 --- a/res/values/strings_nl.arb +++ b/res/values/strings_nl.arb @@ -926,10 +926,13 @@ "waiting_payment_confirmation": "In afwachting van betalingsbevestiging", "wallet": "Portemonnee", "wallet_group": "Portemonnee", + "wallet_group_description_existing_seed": "U hebt ervoor gekozen om een bestaand zaadje voor deze portemonnee te gebruiken. U kunt het zaad opnieuw verifiëren als u het moet bevestigen of opschrijven.", "wallet_group_description_four": "om een portemonnee te maken met een geheel nieuw zaadje.", "wallet_group_description_one": "In cakeballet kun je een", + "wallet_group_description_open_wallet": "Anders kunt u de portemonnee blijven openen", "wallet_group_description_three": "Om de beschikbare portefeuilles en/of portefeuillegroepen te zien. Of kies", "wallet_group_description_two": "Door een bestaande portemonnee te selecteren om een zaadje mee te delen. Elke portemonnee -groep kan een enkele portemonnee van elk valutietype bevatten. \n\n U kunt selecteren", + "wallet_group_description_view_seed": "Je kunt dit zaad altijd opnieuw bekijken", "wallet_group_empty_state_text_one": "Het lijkt erop dat je geen compatibele portemonnee -groepen hebt !\n\n TAP", "wallet_group_empty_state_text_two": "hieronder om een nieuwe te maken.", "wallet_keys": "Portemonnee zaad/sleutels", diff --git a/res/values/strings_pl.arb b/res/values/strings_pl.arb index 2f2c19546..73a989420 100644 --- a/res/values/strings_pl.arb +++ b/res/values/strings_pl.arb @@ -925,10 +925,13 @@ "waitFewSecondForTxUpdate": "Poczekaj kilka sekund, aż transakcja zostanie odzwierciedlona w historii transakcji", "wallet": "Portfel", "wallet_group": "Grupa portfela", + "wallet_group_description_existing_seed": "Zdecydowałeś się użyć istniejącego ziarna do tego portfela. Możesz ponownie zweryfikować ziarno, jeśli chcesz je potwierdzić lub zapisać.", "wallet_group_description_four": "Aby stworzyć portfel z zupełnie nowym ziarnem.", "wallet_group_description_one": "W portfelu ciasta możesz stworzyć", + "wallet_group_description_open_wallet": "W przeciwnym razie możesz nadal otwierać portfel", "wallet_group_description_three": "Aby zobaczyć dostępny ekran portfeli i/lub grup portfeli. Lub wybierz", "wallet_group_description_two": "Wybierając istniejący portfel do podzielenia nasion. Każda grupa portfela może zawierać pojedynczy portfel każdego typu waluty. \n\n możesz wybrać", + "wallet_group_description_view_seed": "Zawsze możesz ponownie zobaczyć to ziarno pod", "wallet_group_empty_state_text_one": "Wygląda na to, że nie masz żadnych kompatybilnych grup portfeli !\n\n Tap", "wallet_group_empty_state_text_two": "poniżej, aby zrobić nowy.", "wallet_keys": "Klucze portfela", diff --git a/res/values/strings_pt.arb b/res/values/strings_pt.arb index cf3adcf82..a126cd2a0 100644 --- a/res/values/strings_pt.arb +++ b/res/values/strings_pt.arb @@ -928,10 +928,13 @@ "waiting_payment_confirmation": "Aguardando confirmação de pagamento", "wallet": "Carteira", "wallet_group": "Grupo de carteira", + "wallet_group_description_existing_seed": "Você optou por usar uma semente existente para esta carteira. Você pode verificar a semente novamente se precisar confirmar ou anotá -la.", "wallet_group_description_four": "Para criar uma carteira com uma semente totalmente nova.", "wallet_group_description_one": "Na carteira de bolo, você pode criar um", + "wallet_group_description_open_wallet": "Caso contrário, você pode continuar a abrir a carteira", "wallet_group_description_three": "Para ver as carteiras disponíveis e/ou os grupos de carteiras. Ou escolha", "wallet_group_description_two": "Selecionando uma carteira existente para compartilhar uma semente. Cada grupo de carteira pode conter uma única carteira de cada tipo de moeda. \n\n você pode selecionar", + "wallet_group_description_view_seed": "Você sempre pode ver esta semente novamente em", "wallet_group_empty_state_text_one": "Parece que você não tem nenhum grupo de carteira compatível !\n\n Toque", "wallet_group_empty_state_text_two": "abaixo para fazer um novo.", "wallet_keys": "Semente/chaves da carteira", diff --git a/res/values/strings_ru.arb b/res/values/strings_ru.arb index 0ba732a1c..c020b384e 100644 --- a/res/values/strings_ru.arb +++ b/res/values/strings_ru.arb @@ -926,10 +926,13 @@ "waitFewSecondForTxUpdate": "Пожалуйста, подождите несколько секунд, чтобы транзакция отразилась в истории транзакций.", "wallet": "Кошелек", "wallet_group": "Группа кошелька", + "wallet_group_description_existing_seed": "Вы решили использовать существующее семя для этого кошелька. Вы можете снова проверить семя, если вам нужно подтвердить или записать его.", "wallet_group_description_four": "создать кошелек с совершенно новым семенем.", "wallet_group_description_one": "В кошельке для торта вы можете создать", + "wallet_group_description_open_wallet": "В противном случае вы можете продолжать открывать кошелек", "wallet_group_description_three": "Чтобы увидеть доступные кошельки и/или экраны групп кошельков. Или выберите", "wallet_group_description_two": "выбирая существующий кошелек, чтобы поделиться семенами. Каждая группа кошелька может содержать один кошелек каждого типа валюты. \n\n Вы можете выбрать", + "wallet_group_description_view_seed": "Вы всегда можете просматривать это семя снова под", "wallet_group_empty_state_text_one": "Похоже, у вас нет никаких совместимых групп кошелька !\n\n tap", "wallet_group_empty_state_text_two": "ниже, чтобы сделать новый.", "wallet_keys": "Мнемоническая фраза/ключи кошелька", diff --git a/res/values/strings_th.arb b/res/values/strings_th.arb index 29764b302..71f0fdd3a 100644 --- a/res/values/strings_th.arb +++ b/res/values/strings_th.arb @@ -925,10 +925,13 @@ "waitFewSecondForTxUpdate": "กรุณารอสักครู่เพื่อให้ธุรกรรมปรากฏในประวัติการทำธุรกรรม", "wallet": "กระเป๋าสตางค์", "wallet_group": "กลุ่มกระเป๋าเงิน", + "wallet_group_description_existing_seed": "คุณเลือกที่จะใช้เมล็ดพันธุ์ที่มีอยู่สำหรับกระเป๋าเงินนี้คุณอาจตรวจสอบเมล็ดได้อีกครั้งหากคุณต้องการยืนยันหรือเขียนลงไป", "wallet_group_description_four": "เพื่อสร้างกระเป๋าเงินที่มีเมล็ดพันธุ์ใหม่ทั้งหมด", "wallet_group_description_one": "ในกระเป๋าเงินเค้กคุณสามารถสร้างไฟล์", + "wallet_group_description_open_wallet": "มิฉะนั้นคุณสามารถเปิดกระเป๋าเงินต่อไปได้", "wallet_group_description_three": "หากต้องการดูกระเป๋าเงินและ/หรือกลุ่มกระเป๋าเงินที่มีอยู่ หรือเลือก", "wallet_group_description_two": "โดยการเลือกกระเป๋าเงินที่มีอยู่เพื่อแบ่งปันเมล็ดด้วย แต่ละกลุ่มกระเป๋าเงินสามารถมีกระเป๋าเงินเดียวของแต่ละประเภทสกุลเงิน \n\n คุณสามารถเลือกได้", + "wallet_group_description_view_seed": "คุณสามารถดูเมล็ดพันธุ์นี้ได้อีกครั้งภายใต้", "wallet_group_empty_state_text_one": "ดูเหมือนว่าคุณจะไม่มีกลุ่มกระเป๋าเงินที่เข้ากันได้ !\n\n แตะ", "wallet_group_empty_state_text_two": "ด้านล่างเพื่อสร้างใหม่", "wallet_keys": "ซีดของกระเป๋า/คีย์", diff --git a/res/values/strings_tl.arb b/res/values/strings_tl.arb index 772ed2cc0..c46d58b19 100644 --- a/res/values/strings_tl.arb +++ b/res/values/strings_tl.arb @@ -925,10 +925,13 @@ "waitFewSecondForTxUpdate": "Mangyaring maghintay ng ilang segundo para makita ang transaksyon sa history ng mga transaksyon", "wallet": "Wallet", "wallet_group": "Group ng Wallet", + "wallet_group_description_existing_seed": "Pinili mong gumamit ng isang umiiral na binhi para sa pitaka na ito. Maaari mong mapatunayan muli ang binhi kung kailangan mong kumpirmahin o isulat ito.", "wallet_group_description_four": "Upang lumikha ng isang pitaka na may ganap na bagong binhi.", "wallet_group_description_one": "Sa cake wallet, maaari kang lumikha ng isang", + "wallet_group_description_open_wallet": "Kung hindi man, maaari mong magpatuloy upang buksan ang pitaka", "wallet_group_description_three": "Upang makita ang magagamit na mga wallets at/o screen ng mga pangkat ng pitaka. O pumili", "wallet_group_description_two": "Sa pamamagitan ng pagpili ng isang umiiral na pitaka upang magbahagi ng isang binhi. Ang bawat pangkat ng pitaka ay maaaring maglaman ng isang solong pitaka ng bawat uri ng pera.\n\nMaaari kang pumili", + "wallet_group_description_view_seed": "Maaari mong palaging tingnan ang binhi na ito sa ilalim", "wallet_group_empty_state_text_one": "Mukhang wala kang anumang mga katugmang pangkat ng pitaka!\n\ntap", "wallet_group_empty_state_text_two": "sa ibaba upang gumawa ng bago.", "wallet_keys": "Wallet seed/keys", diff --git a/res/values/strings_tr.arb b/res/values/strings_tr.arb index 34fc7da8c..828e364c2 100644 --- a/res/values/strings_tr.arb +++ b/res/values/strings_tr.arb @@ -925,10 +925,13 @@ "waitFewSecondForTxUpdate": "İşlemin işlem geçmişine yansıması için lütfen birkaç saniye bekleyin", "wallet": "Cüzdan", "wallet_group": "Cüzdan grubu", + "wallet_group_description_existing_seed": "Bu cüzdan için mevcut bir tohum kullanmayı seçtiniz. Onaylamanız veya yazmanız gerekiyorsa tohumu tekrar doğrulayabilirsiniz.", "wallet_group_description_four": "Tamamen yeni bir tohumla bir cüzdan oluşturmak için.", "wallet_group_description_one": "Kek cüzdanında bir", + "wallet_group_description_open_wallet": "Aksi takdirde cüzdanı açmaya devam edebilirsiniz", "wallet_group_description_three": "Mevcut cüzdan ve/veya cüzdan grupları ekranını görmek için. Veya seç", "wallet_group_description_two": "Bir tohumu paylaşmak için mevcut bir cüzdan seçerek. Her cüzdan grubu, her para türünün tek bir cüzdanı içerebilir. \n\n Seçebilirsiniz", + "wallet_group_description_view_seed": "Bu tohumu her zaman tekrar görebilirsiniz", "wallet_group_empty_state_text_one": "Herhangi bir uyumlu cüzdan grubunuz yok gibi görünüyor !\n\n TAP", "wallet_group_empty_state_text_two": "Yeni bir tane yapmak için aşağıda.", "wallet_keys": "Cüzdan tohumu/anahtarları", diff --git a/res/values/strings_uk.arb b/res/values/strings_uk.arb index 35d12cbbb..73301eca0 100644 --- a/res/values/strings_uk.arb +++ b/res/values/strings_uk.arb @@ -926,10 +926,13 @@ "waitFewSecondForTxUpdate": "Будь ласка, зачекайте кілька секунд, поки транзакція відобразиться в історії транзакцій", "wallet": "Гаманець", "wallet_group": "Група гаманців", + "wallet_group_description_existing_seed": "Ви вирішили використовувати існуюче насіння для цього гаманця. Ви можете ще раз перевірити насіння, якщо вам потрібно підтвердити або записати його.", "wallet_group_description_four": "створити гаманець з абсолютно новим насінням.", "wallet_group_description_one": "У гаманці тортів ви можете створити a", + "wallet_group_description_open_wallet": "В іншому випадку ви можете продовжувати відкривати гаманець", "wallet_group_description_three": "Щоб побачити наявні гаманці та/або екран групи гаманців. Або вибрати", "wallet_group_description_two": "Вибираючи існуючий гаманець, щоб поділитися насінням. Кожна група гаманця може містити один гаманець кожного типу валюти. \n\n Ви можете вибрати", + "wallet_group_description_view_seed": "Ви завжди можете переглянути це насіння ще раз під", "wallet_group_empty_state_text_one": "Схоже, у вас немає сумісних груп гаманця !\n\n Торкніться", "wallet_group_empty_state_text_two": "нижче, щоб зробити новий.", "wallet_keys": "Мнемонічна фраза/ключі гаманця", diff --git a/res/values/strings_ur.arb b/res/values/strings_ur.arb index 874b9913e..d15731cc4 100644 --- a/res/values/strings_ur.arb +++ b/res/values/strings_ur.arb @@ -927,10 +927,13 @@ "waitFewSecondForTxUpdate": "۔ﮟﯾﺮﮐ ﺭﺎﻈﺘﻧﺍ ﺎﮐ ﮉﻨﮑﯿﺳ ﺪﻨﭼ ﻡﺮﮐ ﮦﺍﺮﺑ ﮯﯿﻟ ﮯﮐ ﮯﻧﺮﮐ ﯽﺳﺎﮑﻋ ﯽﮐ ﻦﯾﺩ ﻦﯿﻟ ﮟﯿﻣ ﺦﯾﺭﺎﺗ ﯽﮐ ﻦ", "wallet": "پرس", "wallet_group": "پرس گروپ", + "wallet_group_description_existing_seed": "آپ نے اس پرس کے لئے موجودہ بیج استعمال کرنے کا انتخاب کیا ہے۔ اگر آپ کو اس کی تصدیق یا لکھنے کی ضرورت ہے تو آپ دوبارہ بیج کی تصدیق کرسکتے ہیں۔", "wallet_group_description_four": "مکمل طور پر نئے بیج کے ساتھ پرس بنانے کے ل.", "wallet_group_description_one": "کیک پرس میں ، آپ بنا سکتے ہیں", + "wallet_group_description_open_wallet": "بصورت دیگر ، آپ بٹوے کو کھول سکتے ہیں", "wallet_group_description_three": "دستیاب بٹوے اور/یا پرس گروپوں کی اسکرین کو دیکھنے کے لئے۔ یا منتخب کریں", "wallet_group_description_two": "بیج کے ساتھ بانٹنے کے لئے موجودہ پرس کا انتخاب کرکے۔ ہر بٹوے گروپ میں ہر کرنسی کی قسم کا ایک بٹوے شامل ہوسکتا ہے۔ \n\n آپ منتخب کرسکتے ہیں", + "wallet_group_description_view_seed": "آپ ہمیشہ اس بیج کو دوبارہ دیکھ سکتے ہیں", "wallet_group_empty_state_text_one": "ایسا لگتا ہے کہ آپ کے پاس کوئی مطابقت پذیر والیٹ گروپس نہیں ہیں !\n\n نل", "wallet_group_empty_state_text_two": "ایک نیا بنانے کے لئے ذیل میں.", "wallet_keys": "بٹوے کے بیج / چابیاں", diff --git a/res/values/strings_vi.arb b/res/values/strings_vi.arb index 5b3b08a6b..f9bbaaf7a 100644 --- a/res/values/strings_vi.arb +++ b/res/values/strings_vi.arb @@ -924,10 +924,13 @@ "waitFewSecondForTxUpdate": "Vui lòng đợi vài giây để giao dịch được phản ánh trong lịch sử giao dịch", "wallet": "Cái ví", "wallet_group": "Nhóm ví", + "wallet_group_description_existing_seed": "Bạn đã chọn sử dụng một hạt giống hiện có cho ví này. Bạn có thể xác minh lại hạt giống nếu bạn cần xác nhận hoặc viết nó ra.", "wallet_group_description_four": "Để tạo ra một ví với một hạt giống hoàn toàn mới.", "wallet_group_description_one": "Trong ví bánh, bạn có thể tạo", + "wallet_group_description_open_wallet": "Nếu không, bạn có thể tiếp tục mở ví", "wallet_group_description_three": "Để xem ví trên ví và/hoặc màn hình nhóm ví. Hoặc chọn", "wallet_group_description_two": "Bằng cách chọn một ví hiện có để chia sẻ một hạt giống với. Mỗi nhóm ví có thể chứa một ví của mỗi loại tiền tệ. \n\n Bạn có thể chọn", + "wallet_group_description_view_seed": "Bạn luôn có thể xem lại hạt giống này dưới", "wallet_group_empty_state_text_one": "Có vẻ như bạn không có bất kỳ nhóm ví tương thích nào !\n\n Tap", "wallet_group_empty_state_text_two": "Dưới đây để làm một cái mới.", "wallet_keys": "Hạt giống/khóa ví", diff --git a/res/values/strings_yo.arb b/res/values/strings_yo.arb index 360676a7e..cb9f7f1bb 100644 --- a/res/values/strings_yo.arb +++ b/res/values/strings_yo.arb @@ -926,10 +926,13 @@ "waitFewSecondForTxUpdate": "Fi inurere duro fun awọn iṣeju diẹ fun idunadura lati ṣe afihan ninu itan-akọọlẹ iṣowo", "wallet": "Ohun apamọwọwọ", "wallet_group": "Ẹgbẹ apamọwọ", + "wallet_group_description_existing_seed": "O ti yan lati lo irugbin ti o wa tẹlẹ fun ogiriina yii.O le rii daju iru naa lẹẹkansii ti o ba nilo lati jẹrisi tabi kọ silẹ.", "wallet_group_description_four": "Lati ṣẹda apamọwọ kan pẹlu irugbin tuntun tuntun.", "wallet_group_description_one": "Ni apamọwọ akara oyinbo, o le ṣẹda a", + "wallet_group_description_open_wallet": "Bibẹẹkọ, o le tẹsiwaju lati ṣii apamọwọ", "wallet_group_description_three": "Lati wo awọn Woleti ti o wa ati / tabi Iboju Wallt. Tabi yan", "wallet_group_description_two": "nipa yiyan apamọwọ ti o wa tẹlẹ lati pin irugbin kan pẹlu. Ẹgbẹ apamọwọ kọọkan le ni apamọwọ kan ti iru owo kọọkan. \n\n O le yan", + "wallet_group_description_view_seed": "O le nigbagbogbo wo irugbin yii lẹẹkansi labẹ", "wallet_group_empty_state_text_one": "O dabi pe o ko ni eyikeyi awọn ẹgbẹ ti o ni ibamu!\n\ntẹ ni kia kia", "wallet_group_empty_state_text_two": "ni isalẹ lati ṣe ọkan titun.", "wallet_keys": "Hóró/kọ́kọ́rọ́ àpamọ́wọ́", diff --git a/res/values/strings_zh.arb b/res/values/strings_zh.arb index e032c40c4..88d55aeed 100644 --- a/res/values/strings_zh.arb +++ b/res/values/strings_zh.arb @@ -925,10 +925,13 @@ "waitFewSecondForTxUpdate": "请等待几秒钟,交易才会反映在交易历史记录中", "wallet": "钱包", "wallet_group": "钱包组", + "wallet_group_description_existing_seed": "您已经选择在此钱包中使用现有种子。如果需要确认或写下来,您可能会再次验证种子。", "wallet_group_description_four": "创建一个带有全新种子的钱包。", "wallet_group_description_one": "在蛋糕钱包中,您可以创建一个", + "wallet_group_description_open_wallet": "否则,您可以继续打开钱包", "wallet_group_description_three": "查看可用的钱包和/或钱包组屏幕。或选择", "wallet_group_description_two": "通过选择现有的钱包与种子共享。每个钱包组都可以包含每种货币类型的单个钱包。\n\n您可以选择", + "wallet_group_description_view_seed": "您可以随时再次在下面查看此种子", "wallet_group_empty_state_text_one": "看起来您没有任何兼容的钱包组!\n\n tap", "wallet_group_empty_state_text_two": "下面是一个新的。", "wallet_keys": "钱包种子/密钥",