From 769059232a8ac995f8fe8fa8d369487cb5fb93e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Manuel=20Nieto?= Date: Wed, 18 Dec 2024 16:36:55 +0100 Subject: [PATCH] Complete Browse section (#225) * Refine the invest flow * Wip * Add Invest wizard * Added Nostr part * Add gauges * Fix header * Completed invest wizard * Refine use of IProject * Complete Browse flow * Add Launcher Service * Improve more * Polish * More polish * Use projects + polishing --- .../AngorApp.Desktop/AngorApp.Desktop.csproj | 48 +++---- .../Avalonia/AngorApp.Desktop/app.manifest | 2 +- src/Angor/Avalonia/AngorApp/AngorApp.csproj | 9 +- src/Angor/Avalonia/AngorApp/App.axaml | 10 +- .../Avalonia/AngorApp/Assets/angor-logo.ico | Bin 0 -> 174655 bytes .../AngorApp/Common/SuccessView.axaml | 14 ++ .../AngorApp/Common/SuccessView.axaml.cs | 13 ++ .../AngorApp/Common/SuccessViewModel.cs | 18 +++ .../Avalonia/AngorApp/CompositionRoot.cs | 21 ++- .../Avalonia/AngorApp/Controls/Dialog.axaml | 74 +++++++++++ .../Avalonia/AngorApp/Controls/Frame.axaml | 12 +- .../Avalonia/AngorApp/Controls/Header.axaml | 2 +- .../AngorApp/Controls/MiscConverters.cs | 14 +- .../AngorApp/Controls/OptionDesign.cs | 14 ++ src/Angor/Avalonia/AngorApp/Icons.axaml | 15 +++ .../AngorApp/Sections/Browse/BrowseView.axaml | 10 +- .../Sections/Browse/BrowseViewModel.cs | 10 +- .../Sections/Browse/BrowseViewModelDesign.cs | 19 ++- .../Details/IProjectDetailsViewModel.cs | 14 +- .../Details/Invest/Amount/AmountView.axaml | 36 ++++++ .../Details/Invest/Amount/AmountView.axaml.cs | 9 ++ .../Details/Invest/Amount/AmountViewModel.cs | 26 ++++ .../Details/Invest/Amount/IAmountViewModel.cs | 9 ++ .../Invest/Amount/InvestViewModelDesign.cs | 14 ++ .../TransactionPreview/ITransactionPreview.cs | 15 +++ .../ITransactionViewModelPreviewDesign.cs | 16 +++ .../TransactionPreviewView.axaml | 54 ++++++++ .../TransactionPreviewView.axaml.cs | 13 ++ .../TransactionPreviewViewModel.cs | 40 ++++++ .../Browse/Details/NostProperties.axaml | 102 +++++++++++++++ .../Browse/Details/NostProperties.axaml.cs | 9 ++ .../Browse/Details/ProjectDetailsView.axaml | 66 +++------- .../Browse/Details/ProjectDetailsViewModel.cs | 51 +++++++- .../Details/ProjectDetailsViewModelDesign.cs | 36 +++++- .../Browse/Details/ProjectSummary.axaml | 122 ++++++++++++++++++ .../Browse/Details/ProjectSummary.axaml.cs | 13 ++ .../Sections/Browse/Details/Stages.axaml | 32 +++++ .../Sections/Browse/Details/Stages.axaml.cs | 13 ++ .../AngorApp/Sections/Browse/IProject.cs | 55 +++++++- .../AngorApp/Sections/Browse/Project.cs | 9 -- .../Sections/Browse/ProjectViewModel.cs | 9 +- .../AngorApp/Sections/Browse/SampleData.cs | 31 +++-- .../Sections/Founder/FounderView.axaml | 17 +-- .../Sections/Founder/FounderViewModel.cs | 11 +- .../Sections/Portfolio/PorfolioView.axaml | 19 +-- .../AngorApp/Sections/Shell/MainView.axaml | 6 +- .../AngorApp/Sections/Shell/MainViewModel.cs | 2 +- .../Sections/Shell/MainViewModelDesign.cs | 3 +- .../AngorApp/Sections/Shell/MainWindow.axaml | 4 +- .../AngorApp/Sections/Shell/TestDialog.cs | 12 ++ .../AngorApp/Sections/Wallet/WalletDesign.cs | 28 ++++ .../AngorApp/Sections/Wallet/WalletView.axaml | 18 +-- .../Sections/Wallet/WalletViewModel.cs | 29 ++--- .../AngorApp/Services/ILauncherService.cs | 8 -- .../AngorApp/Services/LauncherService.cs | 16 --- .../AngorApp/Services/NoopLauncherService.cs | 3 +- .../Avalonia/AngorApp/Services/UIServices.cs | 10 +- src/Angor/Avalonia/AngorApp/Styles.axaml | 37 +++++- src/Angor/Avalonia/Directory.Packages.props | 4 +- 59 files changed, 1087 insertions(+), 239 deletions(-) create mode 100644 src/Angor/Avalonia/AngorApp/Assets/angor-logo.ico create mode 100644 src/Angor/Avalonia/AngorApp/Common/SuccessView.axaml create mode 100644 src/Angor/Avalonia/AngorApp/Common/SuccessView.axaml.cs create mode 100644 src/Angor/Avalonia/AngorApp/Common/SuccessViewModel.cs create mode 100644 src/Angor/Avalonia/AngorApp/Controls/Dialog.axaml create mode 100644 src/Angor/Avalonia/AngorApp/Controls/OptionDesign.cs create mode 100644 src/Angor/Avalonia/AngorApp/Icons.axaml create mode 100644 src/Angor/Avalonia/AngorApp/Sections/Browse/Details/Invest/Amount/AmountView.axaml create mode 100644 src/Angor/Avalonia/AngorApp/Sections/Browse/Details/Invest/Amount/AmountView.axaml.cs create mode 100644 src/Angor/Avalonia/AngorApp/Sections/Browse/Details/Invest/Amount/AmountViewModel.cs create mode 100644 src/Angor/Avalonia/AngorApp/Sections/Browse/Details/Invest/Amount/IAmountViewModel.cs create mode 100644 src/Angor/Avalonia/AngorApp/Sections/Browse/Details/Invest/Amount/InvestViewModelDesign.cs create mode 100644 src/Angor/Avalonia/AngorApp/Sections/Browse/Details/Invest/TransactionPreview/ITransactionPreview.cs create mode 100644 src/Angor/Avalonia/AngorApp/Sections/Browse/Details/Invest/TransactionPreview/ITransactionViewModelPreviewDesign.cs create mode 100644 src/Angor/Avalonia/AngorApp/Sections/Browse/Details/Invest/TransactionPreview/TransactionPreviewView.axaml create mode 100644 src/Angor/Avalonia/AngorApp/Sections/Browse/Details/Invest/TransactionPreview/TransactionPreviewView.axaml.cs create mode 100644 src/Angor/Avalonia/AngorApp/Sections/Browse/Details/Invest/TransactionPreview/TransactionPreviewViewModel.cs create mode 100644 src/Angor/Avalonia/AngorApp/Sections/Browse/Details/NostProperties.axaml create mode 100644 src/Angor/Avalonia/AngorApp/Sections/Browse/Details/NostProperties.axaml.cs create mode 100644 src/Angor/Avalonia/AngorApp/Sections/Browse/Details/ProjectSummary.axaml create mode 100644 src/Angor/Avalonia/AngorApp/Sections/Browse/Details/ProjectSummary.axaml.cs create mode 100644 src/Angor/Avalonia/AngorApp/Sections/Browse/Details/Stages.axaml create mode 100644 src/Angor/Avalonia/AngorApp/Sections/Browse/Details/Stages.axaml.cs delete mode 100644 src/Angor/Avalonia/AngorApp/Sections/Browse/Project.cs create mode 100644 src/Angor/Avalonia/AngorApp/Sections/Shell/TestDialog.cs create mode 100644 src/Angor/Avalonia/AngorApp/Sections/Wallet/WalletDesign.cs delete mode 100644 src/Angor/Avalonia/AngorApp/Services/ILauncherService.cs delete mode 100644 src/Angor/Avalonia/AngorApp/Services/LauncherService.cs diff --git a/src/Angor/Avalonia/AngorApp.Desktop/AngorApp.Desktop.csproj b/src/Angor/Avalonia/AngorApp.Desktop/AngorApp.Desktop.csproj index e4646cf5..60ebefaa 100644 --- a/src/Angor/Avalonia/AngorApp.Desktop/AngorApp.Desktop.csproj +++ b/src/Angor/Avalonia/AngorApp.Desktop/AngorApp.Desktop.csproj @@ -1,27 +1,31 @@  - - WinExe - - net8.0 - enable - true - + + WinExe + + net9.0 + enable + true + Angor + Angor + Angor + Angor + - - app.manifest - + + app.manifest + - - - - - None - All - - + + + + + None + All + + - - - + + + diff --git a/src/Angor/Avalonia/AngorApp.Desktop/app.manifest b/src/Angor/Avalonia/AngorApp.Desktop/app.manifest index aeffea76..faab2937 100644 --- a/src/Angor/Avalonia/AngorApp.Desktop/app.manifest +++ b/src/Angor/Avalonia/AngorApp.Desktop/app.manifest @@ -3,7 +3,7 @@ - + diff --git a/src/Angor/Avalonia/AngorApp/AngorApp.csproj b/src/Angor/Avalonia/AngorApp/AngorApp.csproj index 0d45d7b5..d0f409e1 100644 --- a/src/Angor/Avalonia/AngorApp/AngorApp.csproj +++ b/src/Angor/Avalonia/AngorApp/AngorApp.csproj @@ -1,6 +1,6 @@  - net8.0 + net9.0 enable latest true @@ -23,15 +23,16 @@ All - + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + + - diff --git a/src/Angor/Avalonia/AngorApp/App.axaml b/src/Angor/Avalonia/AngorApp/App.axaml index dd5e0909..a405b6fe 100644 --- a/src/Angor/Avalonia/AngorApp/App.axaml +++ b/src/Angor/Avalonia/AngorApp/App.axaml @@ -1,23 +1,26 @@ - + + + - + + @@ -28,6 +31,7 @@ + diff --git a/src/Angor/Avalonia/AngorApp/Assets/angor-logo.ico b/src/Angor/Avalonia/AngorApp/Assets/angor-logo.ico new file mode 100644 index 0000000000000000000000000000000000000000..f75e7dfa8c2679fda036de15d1c50a9d83be1d8f GIT binary patch literal 174655 zcmeF42S8I-7snG&!HF9;h_-4SIO`VNdyl%oQTL!$>o&3OJ=?nXwytX3mDIhpYSn5h zxUdcsivwlk`~Q<%edbFb2`>nk)Bbq(-goD@=bn4tOF)G}sYtEJm{EbNr=nL1h2lqr zLXjhfK0Z0MLJ@;BPfvY(1M*GGpiq=7X^4NOP?YdcD13eO@xnC}imSC0ihA`7w)KaQYnB9R3M zw*y~;hLUu1LFVZJ+5!%>4af)B3G`Nx6_}GOxX~IofjofidV*$vQUPG}I)UaCRX|n1 zFr_Z2s0%3+O>r$?2sgsD1!xbTQAIJ(5mW;#&v0>21TYWtHUUC1Ay6JrZ5#vZ%M66@ zKF7^_%)>qykCW|o1(;2pq{2_;BMeh`k9nBaSn?vFxgpUN*UkXepo3wiQJ9DNHYJUb z=mnfXJHUPuhMC5D%wtYCC!!BU5$0SFhAF(qJh6%B1MQ)k0ViDJYFpGP?E`f}D3-LX z2H+Y@4G+akZ{1IIwDXnwVLoVr*UTvm9NGj>3Va9PMRk%6KgWPv`lv-e*?0C+cwnxJL4bY_8dnSi(lOBA z`2l00|1jl4n76(pGyDE6;M%8r0fqs#n-(ztU?9XD0s8iF1{h`{StT>!^UVOeio zNdJRl=nwh;k(Xno|852*f~JNz)2L^r@m?ALi_-P!dt7^iZvgu$6|RM@z{`+G-7){y zAiE(=dSM#xF%R=nJV8$&>Ok=S#1knT-%vm^k4p+61M?06o**`%{$>LDRxvjsKkca( z;P{Q#2lLhhEGy;!!T%E{qznLMC3jd>=(`cZTp!du)1-YUgE;Mwb;KsLC5~6D2kuYP zK?xwFI08)LJqq)(49mtPv?caKx*qBy-bqrB;Rcd8^Rf)fS|Y|{NRL8X(>V-qtul>b zP2cq;-mmHMA^}(Smp+DY4un|ScTvuG477_`1{kK;(szAH(_^TFn?#7MeHZ18#~{*q zjZfc2J;Iix^C0fUx9_4JQ)7^$@1lNFW00%wq7CU71RrNr{SYmu9t#f+#?l?HBD5Ug-fkT7hCBm$2PBue3F^qBZ=-4ayVv zf_LYzj3&=vcaY@>*e~HY!T~@op$|R3wtyPoCy*LQr9UD(i^W$4paNrErbHUgzD)qv)eIo@{fO%JdiL9c5gUci zN~?jf9y#XuKZdd0r0FK)jPxO z4flrPnhOY_U*&igfMJ0BWIs#^-3I4@b}973x;p^2Yg{*yJ`m$Rit`5BYY5l}1}gyP z)e~4Md}iQ03H=$DQzD@XSY)6ouI9$ZI;cO|j-^6>K%Z#r4_Mv{OaSyNjR5C$6_^ML z0Ar!uv#v_UH)4sK^9R&5=VT<1`UHkY0QSjvJ{lv9HqAP%5$b^YHP*oZq!D8=mCmxP zgLPRe=5!$TGwHrS|IRt!J*n6_c2S4W0eyf}`XeIU7XlDB)=7NEF503FrUQ;cDnbX` z-$YpMv5WS&FK`Y`>0ltz<(_xZuDA*vG!Y4gE8hj|1iOH}#%^dz_nyR*4mu-)pU7mm z$}#UoRqEC*?Z8+E^n*ky^hvg?cWE7_!shHin%5p<7xfD}FkTDdKCku~yJ#ae9oTd1 zqW#!(VDGVuKA6%$LX2IsZ%PLVHFnVlp#zSa`@5}soT$&*tI$CM6s!kk0;VOTlt*K$ z4NxBmEgbI(upF2>pW;>=;uED%5RVA`htx*d)$p%G1N{c$Y$XW8`HP?wOL`b;@rl9b z8APj4XtheUR;yO((Ku_hB-lkyn44A$_`p#T_=9)vDGHi=PjMSr(3Bz^yfDFkNaMLM zp=C50d<9JPiG6(uu7GP`E1;2uLV_rWF^#2w<*XD{${V=mpLIx!LrHd>f1};Aj5+Ct8?<|l!<4i~;vazTB1{SW8rN|rQ#TE1PPkSE zTfi;w57-8(0^TzxLviCTKpQe8Igv=a>22z!AuR*02Y}iT7Z>V}_Qmo?Kw)4?IKEkc zeO?2~f-+zgVA>o&|6)pbRy+;P0Dq7kNF@LfuG?(VL=)k*NaH+m4)_e_3+Q`pfbW5+ zeIg6e2LjGbAfUgMzOPAzIQvH*K_9?(3|WD(VcF%Dx8-u!Fs^)%>Z7&Qeoa{;BT-2ln1O+Dk%`D0e%5@Ks#Wmur7Cy&O`xE zq)i5Fdo!pAjN3+1oWe2{z(&Bjrh@#ySlEX`fHoK($%w*S`<$1fpfxZx_ei!%SVv1h zzd*a9ebLV35{|ne_ziIFeGB690mx#ta6Nwm*ap{mW5D$lAK}_p1Fj>kAKhk1>}4>GUN{!3l5%_yMW!N{e`B z!#(cd%>m1p6Sj2_xS7jfWjgh65l}Ctgf>b)ehlO_mBEn4d(5*5(7&4!&hsBY4&96T zsR!zVwqZ`Ff3_Rj8s|OcVP110x9&wd?GcD=4tQSXTAv~cn7HyD*Cg|r63(yOx)<$; zIf!i?@Z5F<6cL3a*TRN-A4B(|8?;I4$DA(`b1+pDkX$DtOx<%Wn-Y8KUbH8C5&fV! zF*OH5_sz@|Lb|=|-ndEb2bRo%bRA4W8SV$M>7Hv#PM?G7Oo}CQKpW>e_#E&&a2YfQ z<|LtXFWQf54yb3^I_DrU>0b2T(mA+`0wgimz398RS~3S)ka;VRo+U(iUK7ISNZXT! zEt!KHC_u~!_j5VVIp*3immb#~m@CJ0>YhG_`})TcOXk2_-#)hPMZavBgT$bF(SKX! zAhGCPjKP{YNKCpH{kLWgsQcdl&$Ee1ESZDEsC%J9OXeW4>RyZ?wmC@5x)=SAZ4MH< z?!_2P%|TMoz39KGIY=tH7h@1};E9BMfajbJAgPF$13p)c0*TSz$EC|Q$ROU|Cd6}X zT>Y{3enu2H4gx_YYYSVPpI;kdW^v`$i5NFro%l5)UnWF&@TZc$nXYC?!*`zVM9q-W z@WCst8pe@BT!R(P8h#oPtVmaq*C<8Fbo_K6O5y9IyRt0fEMwvt!}}`yjSjC~EK=)Bp0W2Fjoh55Z5scsxk@K%}}dw|@y6 z5PQJ~6&OWIAbuZwEF0i>e*_$VSrC^{SDgC=z?`mV1OI@ZL0o%*95%qubIg5)fLpN& z?VWc2128upQGqqOQlZd)pspw!%e6S}-36BT9%(f$h%^R!!9LIo#HDX!c_$nX=aKeD ze;$|6-YwNt0p#U*U>iscVv~Znc@`W7oJ&iDcDM?>0C&J`LwF6YoKxCWT;hog!GLWS z0NR!ZSW?puU;R8Ik@qxC~x`p&%~d`-*XZ`^GasyDbU|1MW#YgR+kk zfG3DeSQqzdwtWrs1zCV8;U4`2%mMU)mWUTJ-2gj48cBgv2va8qz#G7`c1IAKow(tC zH*g6=fSsTQknWqbXCJT~yarc54?sPe6Z(yI;3QyQeh1Bgv@aHn*}wCkGe{523CBcz(ym!%Kd1+&cXQ&78{Y!@ZQ8>I zP!UingHSLNShB8=?VaRD=r0fmCV~4P4EzL&f!Kt5BcG9;gS&w1DL1fGs8{NjdgeM@ z3gVhS`hnTt33v=<0NO9xkE_4PVp94cm41pgxeL?;QoBX;12OJ5pAq8f_XiaiMT#T7 z2uSsq$0(09%5_u)YzD7@7SNwqJNGD}6RxGYfNMU3F2(eZbV%+5&H>u(J`k7PB8x?0 zypArQlplz#KlEA6K!1=O*h^>&)xj@-zU?yT4r23LxNVcTp;TA!2Vh&jg1GDvS?nfX zpl0r2&%gsP4tM~23-`XUK=`8t2-~{8ZRu+c6#5PX0s4kjpe#seDUAk~1MX3`!Elfh z*h`#HaZ@1n+d~L91}?x>;rfZqpT<=$_eJi{2Lb)g8PFWCuX2kQD&!tZUH1l=fvv*+ zRRSx(O2BK~=!H-voGe`wMW-$^xvFdMLoYjkdO+75TXa zZh~!qX9G)w{()ald))9yajx<}I=h&47K_JT#If%DGs{scJpWk6ga=Kf=@d*eO| z8`zE;)|>}8Ui!L+fbWtlo%@gJ^U+O{VvP-O%-rLb0@^`Ro_lm(CsG?oBNEMAInO-b zMS$0UbI-L9n|#c(UTpo6-W!RCrF(&}0c+? z=U$9IzBZ7Q=U(U_J~qI)e-0AUIbV#+(yOgD;ED#4n$I_<6I*OR%)QE7rAa8=S{sng zeSAI-OiU`W#s=!3<6QU2VeZ8o2pfp&9Z_L7Hjtd>Ug#jUcSOl~ z?#1}c*#PIB--q}IBp07A#%z2w?QhvrW9+#!@&yn#K_yc^zxz|G2WtCPNBfa`)wU`~HnpdS- zsqxTiBb?O={T1J|PoXW0Oazu7E$45S&h_E{QApiaz6tzWW=-!ZAhQRlH%W zx-oO?)Ip3={fPldm}fNMYo-Bn#O9hyf6D&)~!H69UY9)GXF za1C|~L-Xi};Tq<`W~og5HNu(Avm^Q|I^e^&xI!x`#>Ewr$0#RJf2Fo4)Ryk5YaR`X ztFC!Ah`WUq`Y-a$#`WFbiD+)}??miF7EFuocPgTBjf=O)a{`nANkvMcqgOy&W0T&0 zf&9w>_pnI7^?VAPjsxanewKw1CVEMM9{vbu1D8NtG{7&Z^z|T7^5w3~VfVT4$fMeEuFOD|U0azkwk!c5b4tzmkl?v$C6L0`vgR@Ag zBNxZD4Wu)a;P*)$0@@I5&k|{bOo`csXgiAmZHJ$iTOwQw>%dFUKvIAZIM@P=ZAX+BHl#s9W|0`jmFqMy z*${1K8KCX70G0@CXCvUARWFtTVlRtCo=&mklis4P6O$jp1D5W0*LLG-sqNH3UfK@d zb*2WfNom}C01ksJv1OFpqYY8_^!>K_p~5IT9!vmV09%A-mz99~YBLKfpgyP<>W6xY zOPr8l4xkPB#g*A`pXVW-Pw#>PhBQkr*^zM&xCyid{=s!Ha0k{%DP(>Ecuuj@cIb=g zA2tB4GfSi-GKGMnAZr{2a^wC8@CaN1xqv0Yb=eXe0eC3a>2@rxqd_pBu8x5=fcm#Y zIv^9zC=Y=O!ok_4_LFm(1vCLKGSstriAlDA9V(BES&T9ATD9uJezPYeGO>W zO9AIzh&KX@0MAzRvl~HWK>rw<(B5cwHvs!|5p)NcfGKH=M6SiPz*@h+KHdk%K{g;H z1p?Id4#2s327UlVL0rPMHwAEhqrrYa-({+ADUn_m>;aso$6z`r2;!1L$iVq!8J1-` z4S}?sbcpW+VZaAiD@qh#e^`GvL*Zh$QWw+-&+XI^bw!=UCRuQ^H~159UN3{5z}&pz z);r0F5Zk9MuJi?wJE-8o%W5GPYa6$?7*d6=< zI5(W9{va!`m(Z{E1y=#vw8pQ|7862Jp^xX_A4YO zxRgYTiviD9uL1XpO28Q;v^b%`3Sd2;zY7P;0H2o<%2v>nPV(UAXmAJ6u8)D%fP2Nq zmelA#3n2EZdkCvRK9CSn9gUm;)XPmU2)F||Bs(f0atQaU0B{4aujfDwU{6Vb%4xrB zZy_iIwE zZZ2hOC03N~ z2HfA{66RS2ScYXS5n(&D?~h?SqL1;lAzx8ZEZ1tdN88y6l9KI+A#r}J^+SzNhW4-q zxBzoP+Yx?;zRMCxEVd*1N*l6vFQXmo0MCIhFeg=U;~Ajsq%)VvC_ORw9iuMk);MkG zDB%2AB5~OeZD$4G**dB0S?H=sp$%DkrWQ6t-{NbcR$)84aL-cP;XazsXJr#zH<{#( z)cb%oWa)F6up#5UEG6n#0c^1y+VRKSv(UUr5jMoOr1?luVzXD5b zCo%dRbpHdf#fHRrXccOr&!O!s2eh4Lz!DLA*2g+4Thd475jI30(8a<+v=8o2w3o_& z?>C-;-5@=%L=v;#G48*xp<}pVsUH&0W$RFeXCm58b6|-G+exf`$9N3FhUkZ^wIPNzHb|*n|yPu^~}5wkvJtFre*}iY;Rzzb9ZWIIAfa@kOFvmK!yxojvo+K$jsd~GPX+K$kV zupwK|L!D3&_rc__X9=AcUxf`>^Nx{qBzM~pda~7qJ_XwmI0cAzeqH3{S<9Ss39&JqV4<+{sl?-8C{Im+N-c3bACwJ z&RkT?yq}_&vms$Se7{rrQ&fy$%;s#!VLR`QLTW>_n@m9Xoln_zgodOx#OL$&fIew1 z_*DH4hW>#F8@hqklE6+OD0qrS~h!6f+B9E~Y zY1jkl{HT}mKCIOJF~=|$HBzNvh3>B|2D>r0B7lF9Q6mj!(4`M^)+)4`dej=|p~)1m?&q$AB|Y!vS4!z%m+gdwbCKMi5$Fa`b`s6LMyx)){$ z`=FmuhOh_1_{*5OdfX5;FM~gap3M|!; zseHFkz6W>$bki5lEBn(DBzI|m0dlNz=qw2J{AH+%^PvXA!6+-ByFUfkp96qr{p2eA z&f`|Vv0eZwV2!Srm-;#fSO@*i5by>(0zSYNX@Wxk0j@JXMi#FO<6s zsQ=X<58!t?8D9l#@!|Z=;xe3tocmZhpU)eYq zJ`Rg>{xpP*ZC_L?*Bba46>_c*0ZV^ZM)V;uUHM9D7vNa-09$Q;tf3CtehCnp$h`(S z$JSUPzt=2hT!bfbW;&JPT3hZ2|oP^~CkXbD~_rx_RCS2R#4SBE?aNK8JHS9$0Go z$f^@}{5%3!emzJ7tQD>su@9_4IHk1}80Alacr~yQP&e!wp`TzozJPh+Biy@o0@k|& zFmA2T_NM^W!M(Q#utmC}5ZAynP}j-|INznfe!zZg1}?x>DTIPEzyrYgqQPl!0z?6( zJp{7={jRM-UEKn#k9{u(s84Ie8<~Rv>rex0Z68H+k{v&P2drlku+$dvA@3+4)*t7v z7qCUxhXLRUU_S``=?IV)(M4XX{cEa-P z2j4ryNBmKk{+oWh0fs9l*NCMbH~$1F=bI+!WgIGE@biz3g06Bm)k_DN$KU@H!u3&`Kz!TUi z?BghK3y69zA>0>a1J(%p*aOfWq;onI@y`Lzc0T~Na~aT<*g>^On9D{VO zS0HZfT+=St|HU8_NOi(B>;dc{Wl`xa!1YXBwE@=pc=l}!2m+$t^a*_c{hYle3mWJN zs3*~WFv7HH+O{>qIjs+N0`3X4e?MSPaYNVY7yJTV1CEupvIZERACQ!w;)K@9gOwl*uy5Ss z=%eVX*!QF=N_5;C{0N=^j*ZVzfuJQw0}_kyjM)qv1l*h1SNioupfuoEl9J>>XGeg) z0mnlA1bmO+4ic+mL&tbF<$fgk9fa^`kPjqw$$$>>oO&EY1CHSVm;nldq#~cAqf-E% z**FI7SEm8@FYbSdO;VvlH2|N@UIF&`1=t9xf)pUB37>1ZKdl4*0gj3L*A7qzB$mA) zJNiQVehApdC~z3G1?ho3g?`!IzM1FiRzL$dHja_|*({J4eCbg1L!2kCA^a`K3G6Af zO}_On+b zR@9pnc{PAK;C?Ijxt`DXO~3&l&gPtJ+Flt@3UCcdpD}(zoagz}Ku+P<)&q`}dz?Mz z8P!`X{>Vvt;4@@BAct^YrGA%!XMkg78+!rYnQ~r)@GMdn>;w^jdD)khfIg9aQV!wz zW?yIrUFE1yraI^weg|@`0T0wQ1_T-EWW5(a50C|z6TXM(2F?MNA@ot>KzSM&0Qzt_)_}R^0owi^ zLp!wn48U5Eo_Ugk?ThjIBM{#;z~=#;XSffv1IE%C2`|A5(A@Z@g>m}*k1vjb@fLEu7NOM>psu~WyKoc8DB^% z1cdFk5Q$b^rDq;Kzb7}5YYl9NVz`&=1GIbE`fk9qU4}R=R!MTVeW4701me2}_&m!s zz;h0LK7GBg{gw#ZBK)jE`2FN)`$8w#5YPbHD)#}}owdS!fX}t8<0uf%*tC5&V67zA zGmkkv_~Ax;*FZDW!8O1+ATNNewx3+jJWz>Akz*gA&)*4z{^|d1vHefQ?;B5qbPd!u zzG-2+0rK%Xh#`RIB3ndy=1C6Ex|Zs|cptFkc_1Yks|@(vTZXL_`u%l)YbYtd&G9-@qH#XUGs;j z4!{4QK19rT4cOx>(Dv5?EpXUAlwhUAcMUjf-%5oWWslE3;IMroW!f0Ebq&-) zd*b^%4!>`s@=?r|HQ=y)+x2a#q_u0nVf&`EXnUIUEVK#L#P&?=uzlP099v0$+_dDG z*kSvzY0>t3(lxLV)tGuFcG$k{`n9B_KQeI*@UvS}pA*yeLjm9Od<`5TuLfdU0}k7l zSJ&oh^T!Rb2Bg1FTodUI+c&2*`O;0T0asM-c+VrBj^nCH`aHmQJk^1C)^+&(xU?7l z`_gA({vOO$pan;PO{l)N_|+(utFc!1wRO@c!Ph?6o1v!5LWT8)%q|!N`bIS zgptcf;lcC>{s~kcwLYwjV%Ux8VF;@|H2Sb}gi_~3hut`?2z{6>0bLEyAM|Jl2V*=Uj7FUeVHLwM%!7H+htVz)G)lEI z=0%I{QcnmYs8x7qJR+PUbYadw7_`rHwN9&Hy0BiuVLB5**jWP|GY@smdklwRrqpil zXYk!@D%ofKEJx^P+=Kb0;V4>#id|+$$Go#53_xOCK57(KF%Jg7urA2K7>0sQduR;Z z=KwV5l0FYRsqZr8$0Znp*QX=Z(0$!t-i4W0KNOlK>(b|^YV^iSQ>OCt>FkTX`#RIt zX`gp6fOlbJ5M5^G_hGd(?4j2_3#%nz&I{8hoI8Dpoz`ogan6fK=e)cNV;zWagi>^$ z0}$QUnWc}&Lwgfp&WouqEM6p|qXsQAMH+@ZzY}v|L-z|S^#8~u{}m6V!V@uyQgI{$ zeklz|q$$GZ0lKL>bG*S-{H-1SF0QTcxs~0K8w**~bH1eSuuUw#7Mse#f|Nx!Os} z^?0K5;#r*Q6R+)LTPMbAkY@_9_7T(xeZW@0^=}U!aKcb8$M!uiZXZdXw0win^YcFH zUhd~*OZ|#H&jHf22mMbm;1InA^5b#_aPGP9j{G{Lq1E3It48m2ceZDg(ByPxX4L}`Y@4bR>kvQsXf&0>D0iQVXTXWmt1O8uIUPw9% z#M&Q;u$*iEw50CX);_Z7#MlQcMyg!z1B`vZIMn^Ap92O%2hz3wxo#HZ`C;psLi#Mg z_W^SHfIg^CJcnFIxVSt+O_H?~K(EgMu6@3b8xG`p*B75Ng|QD&Aw36tYVQQO_UZ4%zR!I?uC-4)qCJVa<8!8<50HK~xB_vxd_ZD&7RZ3{xPgQe z&hrSscQKqJ&K3Q&9KyPX0pVA;zr^=U(FAoo1?=lXP#ef4QXlXaDlH*b#c|Y=1^2sw zU%*b#17rsYA^aW`-|teNeD3=e$R+gi^!H-z%i&itpuSCpI$7^(kPgTpxlzeszX2b@RE>OQyOTp`K7cT|EMI zfm}j=#kptQOF=3iw>YE1(%>gRA13DA`1%<47K3ttW#kt6o!)He9BLL5#(lX(QZv}M#eO7#gKC=PX0qB3E?XYiZP!L!nw3+XL z*h6Wv9E&}qJ}MPHfLD&i65(?sZQpn;(qEkcUjycek8phz12e&WAk{7X71!98AhtE; zg!`qyeDE)j*6{#w?oTBF^TkJa4)6y@fz;g5rj4e*(uF)$Xc5AN}^ zf$>^=g0v-|0!RtsBecCX;1Hng3%eBSs29?*16w643U&vlKqL_LbC2aYzCDPq-=ePQ zQ%vcK`dtC408_eRxtoCfqRnu;_7?hpH9+WM6T;GcJ1^o~i#(4AyJX&1U^i$6SVw$> z&xlpQYVZt*zVI3ZCW1mhE-8SDRN!wQZ7U4%^`JU%0r3&~oLYcB^*NBX6O8yIPy}$F zqoe>+fza_`gmZ(05T1pkKA;KWw1EzQ>w@b;^q*^ydpvE^(mf4X%}Qb1nG9|N(FU(i z!AejGm|81Hj+ap1<-t-wA0}=49^%u%7eLGpf;I`CN2o^)km`}=y9=N{pdQNrVUJu} zUxS2_v}lNHPw3z@!oL7xyS;@p?(v_2_zK6|2b>4gg=qUV!UsSrkRI4uIClE5y?||t zesCTB0S15^Aik0Z6`1m)Y;!-@1%w^~5zYw`Qfi>F5Fo}cy*@_z5>OsEgZK#d3Z8>F zW~sh8_KSe)K@NSR8mq(|xoMB*fS3pBfaj2dpf!lEJ<^vH12e!~Al0!5bM5MUa5;|fcxRcmO|(N_h#e$i06`3pfZT>ev}Gz z_=2^7`ioR@R}SX4F=H=@C?a4MCgrYs;l5TkQXEs$&HSF11qcR3r-q+7+Ax z(mnny;zvM7kO?F=;n|=q&;XuigdI=^XFw0Y^G|Y>)EHPjuoZ*@F@Elk*TD$j0g}7$ z95V#`38ZI(mx%LOt}#eXX9FjUrzH3R{0qdq^U65W%K)AQJ{6%(yulps07!N62=N7g z=c1&plYAJ%P;d=M$4Fb}S-(D@U-(qT6$7sWwg9P5q^|gUKL+FnNl|K|(}w}~bussm z2%iAl|FZ&z=rzFejvqJ%s3V~-o(-5*8ziM?Ag+7%Ta1HO+Vd!o80-NcPA0&y`&<1-U$U9!)w52-NdlRa}5;+lfi8ubbJTlso)F1JReiI z=a&YH0pAy~k9?=h=i#IxrO;98lzo2=_`d67i#s~d2b>4=t77iOH5zFb!2pmGd~D%! zfOubU4`H4MlZvE6N7n+OTZWnTF@(=jO~Gy;))V{1`R2LwPeWMrmHuiUXaPQEpI4!M z(Wi|Frw2(%c(#8GI0jzpfrJ$L(ei+M&l4bY$t%~>3{V`<=T8B`Ux|F7NLv9af)pSj zr8XLS1lSk$qY+4I!nLyw2z@4`5AZ^}D)6_YefERzmbsRAK9QdH7_J6Z1Man=&%6eK zaiAbb2%*1XKSUqcU%op`io!LYkUk(Y+Uo*N0_h(A2JzoPN01Silk~XJ8XN=>K+FO6 ziZh@G$Oh~wbx^rNd51AG>7 z0@e!4lmK&p@jKdwNSh64CvpmP!@Ajj?)yo3?W6lTq5aa1#oW-oY3FiDS5zeR)qIb- z9n=Gwg*0qHwhzNhO2fg?u+Bo+0^O`)e5+F+TGrhqW)%LmxnU7CvAV!gBclPtxjOHM+2mYxIT^Z|Tl$1^_Xg=e-RKyLX075)j>2HP44L z^oy*Uev-OMZo+3+sSj9*IPG2z@jxX~AHdH|d47{iSeFWjwSN*}wkd}gul)_El)6fe z(inrHebde#f?7Z>;d-=}51>DxUtz!52K|j(@+qu+p)1<;Wd-?zs>X*X@unwLn z#oDKz@c?oN*ZwLX^sy1)GM%>eedQ27h z6!(2&JsA4{etsjDNPPg$0k-&nLMV3$(2n@7?;9YOaNmCjST~=CK81ZB!~8(fBgSW4 zd-;I)oCEl-Zv+r${xb;Y2Xct<+UHp)xu5yX>8$~7h;zVWgyr-B{ZOCu98lC;CrqS& zjU>y+W0EXrA0j8b>V)FsU z`~F$ zc@FSEv!?)Ui+eiX<(u*WoabSH-|J!CbHEG8A!$*`D!_Wlr+nte@J)(6&jAC_Vq8Ap zGvqN|`zAYTLn7C{m1;Ly2bkd`T*na2NYk6XX)(?*|l?R4iTl^#6l_T>E|<)b$Y1?}vg$z#*nJKp(Ich<#GdX8}*td&*EZ zeZVNda{%XgD3I>^1rV1*xbHj8{MKobYhLODZ@llz)qfk*nIwxyeE`n`a{7Ql zs89F+d#rt)`Ni6&|7r*vVx0!KUX0%d$hC&(15N|!+L!D1`_rOc>At@aamRapD8UBd zn&;Z*Jn<^mvjF$_Hh}N@NP8gXzW)&QvCpBP5palY8ZdPZV456~0+o0fU|0^}+FuET zU)hAPW9`RJv(j?__fk2}0rBhE|Ce?=@BhC};+w+tE`2A+?+eLw4v25xq~%TR`-!oi z(mp4Zu+#_e9FQ1&fMf03&ziW7q&`5-&jsY@wei|_?E7+P^}{;s^(^pVE4IaIp_uf{ z-`KWl9HnB>fIXiDVre$cTaGh-oGOwngY+DbSe^xp*M1|}M(e1^SOdn-0z3zN%rmxQ z-#4Bi`^Tj|;A1}v7@zqa`@a3>pX=TDa{>B=gcirXpU@hA-(F&P7BJrT9c%yn{Mb9h z^)B@Rd^eDgJ|GR+lfLKQjJV@HKa`MwB0UE@LA#76lt|b9Q#9&W`w6A__w8`K8^06e z*}&f7*!S(NVaw~6`hbLb7Lcy}P;}L?_AQ?;xpQ*8OV0uJeji}G_POu7$vr4XeO76J z&jQ^4<^GP4sZP{H;=hKrxbHVHmC2Eopc>#gz}N>cO>S|V`Q_HAeDxWh1MKlEAl>&J zXMXwSPL7)F{VZT=-_IaN#~pRZrU85U0Iq$p?>o-?vQ3$+6&XJZ$n{Q;Ykvh0-|77s zVaJ&tN=SrakIw}hXZ}Pu(Pp}2{45Y(AHXyJ3Lw@#pZ6X6K9rD%Mb2{o*S`2(pX1D* zh$mgrHB-+5OtV%TXMSrnmU!~ZaSo84`MLI+B%a|pdJ=~Q;`=OMyze{C{BbBe5#ElE z4{)6M6XAqf*(F<_1srSNN<}B)?6y1$7@zqa`+g#x;5fQw?X!UKyFNbeJKpuhq2xq< z+nRHLW8Y8YlW9ZuEIkKs-(L>IyS^<5JJ!Ap3QvSZEI9`lul=Tpa2$><*`|TGe1PN3 zZ<}6|QmNQ{fbrUQocWW|%v#o0Q$B#_{nS9Z@BfUrW8b$-r%5fB@v}f}48Rxs3wZA1 zdw$2h4<#g1G4=slG0siEapq5^6K-NyQXjy76G;5~fR43qLRrZ$$=C;oweQ&Xli_5W z84~}U;YUEsJ@@~HX7W0clb;57zTXD;?*en~M*=#abKgquM}~$ z>9|7N*WFe{ypOxZC=@=DxCj0T7Q|Kh0x=54fsa0p0OD@aIJRok;i12ef?@v`SG#Bx zZsNW+SgCQ*stxflg*Mn(4BTN5vfp){nRR)b#WhsvsR`@J~0Z$p-Cm;qZrS@ zd=QlaK@}a8GfyZA5B|{V;=v5MsPRL~qRv3AP-;Xx1CkI4V5MxT3JRkNT=a4DMyFYJ zLL02h%X(2p7k5+hs!=Gz6c}|Fzwe4`F#mB(T^#j#XgS0T)N};0aR$+6H#O2@&@Y{Z z;G#jCHKUlW0$#M7V_s2#53lSEubgXM(GYHWNXntQU{s+N^&qU#_0&+WE-x!I#8s@@ z13fatb#0(-LtIysVU7Mi;%dEW^l>G}qMJ}%JWR>1v6Gl!2rR%5*Y_6|AmZoKf7C=Mqpt zH~Qh~6o5H>zfLhaecVT%AEV*?;G&OX==!)y#BopJ7f>^f`t?_=ze;Zrvr(&5G#*W35|`teS*zY^*V4BYVh?}_5o+Z)$i_@N^_l@K5q0-yXwox4R z{DBz9KOC-P_NO#!Qa62?T>Shaef@g1TEGz^s8qP7!lmP&4LukeIH*Z0<%Ly47bz5_ zR@bjpz16TAp-YGFTGD#qw&j~D6>?tKWa7NklYKL09Ditqr&IneEwbjUwd>~aUN_er z`1R)f(A_V0|1oddmG{ztQvyF6^JNZH5HR(Kdk027bQz!wSu=V&a?UCikZ=3curtrbe7T~^*x|~& zzF&qqmt1r>-Mt$ZHs5)6zDU$RfA#j*)g{O36YaD=wAvl>v}fM`oc3R;Hf;5d1uhq3 z8r97n-Rwfo3(A{SRAVv*DBEQ3H?p6y*T6xVzUrMt_JoYqbkc-sI$sFvkYdU7;mV1B z{Bl;YwYvAnjf(@*Oi0yp)qj4ydj}}?raqH0N1cXqoo|hQ6tmV_TP@f}-CNT=xM97V z|892e_&o~_I$P^%;I603>rOkI`=ZyJluhcU(X{Yh;SrHN!2d>}Ze>%QQSK_#E^FlS zDFp+MrCV`bo5|m2#6ypo`_wH`2b4dZ@?gHpXyeSqv>m7Uz1-t8A=R;Is#F!6+cs#M zw?g^Qd8HrC8m{z zO)>E3v-3U2PSBK&>a1zpc9yzJt;Tah0^RoJ`XN=#7Ye^xoz*X0bJUrZ>2%bA{n~v6 zCyj15|Ha63f$jkXTBOd^|NHxj8=bDq5?RVc+Y%Mcl)m)J$7*VEUkI z;|3|$KGIYPOBYb8O{S95d)2!XwQb#q$Ik-xsb^QZI3h*50+|Q>oAUM7G1JOve=VJI zuajz)X2j2RH6>SRzK&_QMU}6eYW#tF`{X>;LSzQqzHvaq{PNEz6!kyBs-Z;HYxL?tn_fl4w>ErI7ZEW^qn-p8>X0MRxWn^So zZQ!b3LIT@NY&J{NDPm-b?EWlKI@8TZmy{gKq zXLX}v+)9`J)9=^4!<9pCFZUevML-&AdH=kuk%i8^-CVwYXZ7Pu+fnNK;fgKQGqlt0 zEPO5MwewIXx65rY2a&E(a|d~^NLxGuOI4a%_Tio%d;7dR{L(dIuyQoCQ#oz!I(Y*& z1^zkzz~7^KU=HBn0n!U`%n1oJhkdrkt+qZ=LmON zb-apt*f%4imQL^sfA+JgDy*T!lavu7QvB@YpQAwcRHwd;$-Ndc-DgCKetl+lx#F9l z!lbYz+JP6_o>OgUl=9H@z`DUjf@{z|H+{1+rp7{TkBu>#)-KAY40rM>n9BXqu!<$Z z12YCb+Lm*Xw*5Ez)RkRdyDn+aaoUevYSnKMqDp@{>O_RszNwnhx&~JbyR@xo*Tp|R z+SdN>6t`zr3fppY->{r@vNm$r`dPbhkMOju8qd=FyvyxUj^l$A&x5;aYe#g``epKa z;@2Qw+wZ?Cc;l=87B0@)YoFpsShM=!9vwn_YOP&5p?_!JS_@n z`IJZehfVSeTB7}RP5IFEo%iM&TgdgR6wpXZ`xohs zH1xjRPF3o4+fn#_4g}Uy5#C#+kF#O#G8Q+t_RM~ccnnH{j)R~uNLs%mB0QXZK2*v zVf0>;)}`8VH1PhLuF%Vk6zku>C*9ol)Ne{}%@5;?I;}(E_ZNQ-?E0r)p`$TtTa_ty z@(ZW*>#}$p?9p|hw&Yf?0QZ>Ghu3$@rd)k&;mpjVLT^1U-(rb-a7&l{`Nn?NXKLw6 zlZ$;3I%E+XL&p-F_5-PN7O#J4O;EX$Z#%et`FDZsPTDIg26o-2SbZ$us!#p!pbVGC zJgVL6yWotMnzXI0=~ZNIrI?OS23}PyC^#fo5t6cOx{MIvh+&6+0gu6BWT=48AS^`Q5&irN|LuBU}>iOI6rb$YIb4Q9+N)*`z2sw&|@7q&n0zIs+Q zaoC=_rwa^OG4T6)ufmFaCjQZCkY?Y>a|73&)ef6KKkD;KpH)$eN;~0; zESIWPaJ!s(Xqv4qB{b<4&T+b&`oh}|jhB2Ivvb47kOAF8r&WGBW?ZXbJAP}lwXWu? zOaWD$N|o4EC->c-RlROp7;?1Y168H4&+e7pGxu8QYiTA^m`ro4^rwsXaRJLd;QT@B3kHv2Dy-GdkBx-x07 z@=Na(b-ErnwWDQ~(Dl2X22Bcy3Tis)sw!7NwSdAuJdO!()+q1IvxlqPsChfz=^@H) z%_fIcy3=9Qj4!>4gg^T{`uHnFrN_@6Z%rHhbHUEu!TshIbqYy&#kXJi3OzbLQKgFM zH0EjTaxbs{ta3}!FhlsL-8;ito-R7uJ>$(6tE!yd_VMt6FmRXlI}cIo$B zRm)!njo*E1zjD}(@HbVi4E5OTJ{#)?3uSAoMd2QI*8~;&qV>e@f_}?%>`a-9+b=b1 zU7$`U^=8-cpS$|adgwI0(wv&!zqdc#u-AZ}mbd-$TR*QVU0$y`yzlEdo1aw31xi60` zO1sxxRa-Mid3;0a(EsiZ4j<@w$fa1?Vw!s93|tixOr zZ{99n_VKemcb2>?k0a6baXzn9MPsgCZ~SGGMFTVTopkqy@k6tZDf+y4$2w_Cjtl5` zaBhXj=rZ-v-CdXQhxXdV^|#J>y=qilpO}uC+*1aQZ@V_%*xcJY`p&+dFSzZ=Rr|H= zB3i3DuG)zHPppefvG=ywS_Qs*|$ofjOmS*Z%8ngGJiwKWn>Z{W0QaZI9qW znyX(NdQdTVJ$C&`UfwGTh0ZI!a&KKtd2h{2*9GqWtqPWX5IF3o<=3;HFBXt%YV_!Z z+Qol(&hE2t#_>gOzHn-~V&=gd+kXFR!rk!uPFqimNO5{{=;!Mi&%8a;$1hM@^=RK{ zZ{MqdW$W+BdFA_()n)bV@%G`dzs7-hv;|d>ZonpkLYHu=6Y*stC^XZ~a73UWo zl^)A*m}~Et@WSD$63_R|%Go{I>jJde5({Xja?v zc*vGklS4z+*1ojH@2l6dzPTFIeg6C^m%{(*G5?(EyR1Qh>07&v+OIy+?AFRcq0^ex z$QOEISozx&G-qko9#u%x(qGtb?*e@b=!?ehA=LsaTv52Bj-R*eoX5;&_vvnPRTGXy@^ zcX;RzZ8DYa)#u`|lUb%riPmI}igdl6qRZW{U#wcRXWP@j?<=%cmCO?v`6yeU6$KZA}e>y{5s zQ`vE(9Y07}^W^DewU>1Et(Uh~Rj0wbU1rzJ?w@JQV^#TIVs;#h+4}U^nW%v^+C`o# zH@e%9f~`}8WLaNAGbGKe+Sk(#tNOh7e|54fXguud^2HN#-*j47`?H_dj_;-&o<1u2 zTbzB`Wb9envv>LYd)E7(c;$NZyPbLdA zY?%<$d{NqyD?0lAykA|{^+H;#CYRFF!tO23R_~>Iw<;rZ-5#TT*1S`ow%5bjBh!q( zGPY;t(b2Ylq%80kFcmlq(7Y{ra z4=P}li9>w3?kAfUYAI9YcJ|hOYk$hU5}j3a5x- zb*J^~m+JU%Wz*o-PL;OS#W1ea>-bMl`Nsnle@^`=qu)O&r$zmJmJix9qG*_NoohJo z?9Mi3=*Bx28>b&p^uLZ>y=FaqzVzQ^?w4oaxvkvJW=kHN>FizL)^%0>5xr_g$Gp4} zb?tP&!Hr$2oOqpMlk3q1Y3tpn>t8DG{Irup#}3R|@k*rwv#)N7d=0xOT6KBVX?Ma# z^oi+vY@_q&s!rj}18X#$dg8&6`%ZHQE7xV{S7z?uCq*X@J@k*$+%2kHcxe6h`2(kk zvwL*O^vwum{i;rRSEJUI15;GowaUBJH=RpG=C~SlqDOS0)ra=^7@8Xi~$A(l(`)i)BCv@xJy7bYrQc(-Ff1JnDm5bMq z72CYRDm-tKq6S)Mi8)wzCHGHne3ov1=~v_6Rrs5sL$qZ}YxCD=KR(@}yu+$JZ=8Nm zRj2x$HT4&`U%Yho^M27Dg>KdVGHvRcwZT3&l#+dAxmXG|Y`t1hwUJlLj&9RuZdB(rWU+mA6 z_tHMtrQTb`J;yT7gK4xWZtuQTcSWbFibBgfsZ}>Fc+csOYw;uR-m?N5PalI*_BZg>CruIJU%hgWW_K6=-~gX-&@$Nw?6<_=Z8a8>zBV=>7iU7JS!H8~_|;FjBwmyU-v z4qn`}g2(-eUH`7D+34KxH}xHQqD*(+Mvs2}Aj{FsZ##?+dRzI-<*6_XWe zKbi2YYt!_7Di87R=Y6DCz=5cUvfAigUk~lj``A%sz3F#$#zdcV&avTP?z<~ILi1mI z_U1{+D@7{g4;@!*C62C*)Au=$`f%tj#aZ92YX_EysdR7d(|VDfRU6e>z2W$XYPnlR zJXxyw=IHCg5fu~_vPWD#ykqFdnDcF0rC+e%)$b#&k6re|kYyJ_R<`Id@Pa$z>Dp_jmg_mU3Bcy@qRz%FW9!- zgnVbq%s!FjNX-Q`z0W?J5I)Q)wE2R;B@SF%HofKLY7vT@FV2pylyckZ^hKSvG;qIh zcx2W4*?W2flzaa5l4++_Eqt+OWv5}U=SBVZr1rk)7ZfK}Z}*&WtoXRUqkWXsW^{c} zwN>Y%%Us5c%|1Ox_U##4j@?}NwbOr^RAo1w8j-@w|MT1R12;Dd@d^iY>lWl$ z)Elqm@OZoXY1V!ze<}RRZ${ww@3K8V9<%n|?0muL?lth4;#aTbqnXv5N4X5Ed%I)q zhv~b|{`z2!a-a9t_=Obh^z)aVO`lY`le*KUF1ga|do}!g-{Lp4E0$({SbWm7=nlOn z1vS{){l>9+%Dq$Wx%YD&p6<-WhTnZYBj@kslwUvHR;v$Ql;-&QV<3p-yg7OdbIX=km*G4XQ!{HTH@IR;a$5!_)x^8veF{7XU z)nI;(e&rrNTkX>B)){r=#wUXw%=upcqZ?f0*YGpoZ-Jv2d021=@aJd<$p$JXDEpDr z`twNL*ec;y60S!e}_yAn#}~$`91C zfyiuR*}jfKi+vS-*C4Wn*8^`yAxx}g*O4#-e=Z-VB4Ku z|YH%C_cRkEeh3I?C%5bLHdFD$Zfv~HSbjV_j}O8el1GE#w@a`CoUHd zni_N+E$Rid5;^pOufp%@ex3G<{i|Un@Mp*xucx}&{CZSEy$02^E6I2JQ6lgMXz}R8 zhu!4@LKT7YX-%)XWtd8`^*@jHN4z<~S6shyJQ#nz%pURp2K@@h}1AH8L4W0Us zSF?{mJ5)ZRB#Yv&W%x7y*P#`<(-{YxfMmrFBf(Ckx_y$s=rNQOJdyh73R<0MsLJH) z5m*VlhRz8=n@Sh(UWPZtDE`@sN?o05nM%o`{J;X>Yp62f>y%6?A+AN?!5QeGw})Ef zP&sxp<=1UH(oM8XC8T8z6uDp12@jY!9nGbGkoK$q)IuIr2>yUx|O6{0>?DZvlTq*DUHXDEaxeJY%>O~s(lTahge-rnX zTFqhy3Jcbtu)u`_TT!U66uoc)1yeX`n%AUV&6ecS21ommq@EE0FJHb!at4T z+wsV{hqUVlpd{h(sH?6E-MrnjP`qX|gf7&*cs5cvz7NIvNh8?%P{?!#dhx$ai{_eI zbpZfLe^;UL(wk5$I|;q)q4S!EnqFMBU;r%yPSjy^4p}4|I|;q`e~uP`o`iohh!Uy4 zLk&=if&W6!kC7rd81Mm99oj+V=}LQ$9QsRW%-R8I zpNNr67Bvl>iyDWXL@`^^LNI`8xZg)zbxE~eqxHz4j>(JAtcYi*e&X_Clo)I&g`Y93 z3AhBc$!?{xH{kLL*CO%9q$+H+an^=j+T+mUMVm15>i9{9ZD8Yq|L*@R;~h6i|c1!gJQYu zsKhf9ze|@vFZ?W22R;UQ0xuT6$EpQ!lR;Md?P$@z0F{8p6MmWZqi5q5G$iG2!dsiS z6`imEIQF4(;Y!pV`ywj&^blSMCISZ|A<^Mz;n;>Og%KaK&{UoepuSJ!<4c>~)De?E=y)SGS;HXMygNz>5cu>+G8 zr^Pt5YtbbrVfPl)y_dA{=nm8$ax1C`+=V>Dj#Pwp>H^@{k1WA5#vN3yBkx9Y^!_Ib5hl>)b>s$iVRm5XyA+Qa^KRGWXH@bfe(&-@cw zEys-PSJeG@$DtD7hfp?o2bE>TyU{SyE6@XAn`?v_hhF^4seV(Fo#^@bYv72&ccg9D zKyLmV)Oq+LRBhUe7NtStt!x1PmGVt)JA!$@zZ2fet{)9wxD#o!4J# zYg27M`EP;$g{**u1;gaf%lr3ePlD&DyjP){=kO`i0zQQ}UVKpJ;6-S>`YQZ;3A&$k zz=ugLVYVF;(J+QhRF3OhiS8C8@0^?V!5457WzGQp4b6kA)M7e-%8Wlj6KD=e`y?V@ z9xCbm09nLJI~Wb3dj1tCJP7r4q`_p=MS2CANAVJspYQ!hk$4O#EMRGr0kbGG`w5iY zt>zeekOy!y3L8LHqA!KxcMPGL|I?_yU>#cNrx8v*Wzj=&2*a}CE>y1Sw7PT;+MD15 zz`KBxk>yN!CO4tD`9IO@hNTR@WN9)6l_=kdv=TAWNLK6n7Bayyd8R@jSY|QwYa*W04nd z3@QutAWvW?>1VL(%~+(IyZ~9ri;)+U6#Kq}T=2+C>bs1VcU!bxS zcNZ$leWLJhClN%`l<#5z){8M!ADrNTfpvC`s)Uzbt1CsO>=B(MO0&=;C7xlDoba zS-s~;zE@5twG5TcPA8tR+ubO%ya>I>8>xJ+`U`*Wdni0`p{egW{WZgzv6dRK&yXA< zwH#B?RMwF7znElKDvRQ*3xS)FOI@kvz8}@xZ$>wh21^ z<8UMc9`tq1`>S@dA6#Bcp?qbUu1ZmUNy~9zd)YCJmOJBjz^)(XOPNpCzbEXZiYJ# zkEi+$(6Puv^@S8Kq0o0?+83lA^r8(qO09n$S^o>D&6>GkoyVg1_&%zW;_g6o)_+E$ zzGH|nUAya1NbY=ZmFMyz$`=0%dg#(Pmu{34`$rVFR+FRIgA#n7Ed1M8+NHBdTkq(MB!pflSN68m7WVYfD~P`NAcY=(8d2eiX$tz zodYP#{7ZDR=M%>R=)!{2fX`B$taz|+En7|=^|8bawsgg5P3~&sl2GUa^sCCoS0MdZ>^r`Xz=Fs=!H&d za&bRTqnG6p;&S(=A>(unT5u~>DqQID6ZFy^O??uU^U*@;^8y}566uC5?2Sx{Y(QnbrPNR0 zvLCI`E0J~IUiiJ!3E$jqWHFCIi@_AM2&6q9et+Tk-MMUKc+m<;XG_ne2Q9SQ8M#Dy z49c~<6}>Fy7rsB~W!Z(Y*tenqoOdxiXf;j77S82ug>!ie!@EI;=tIxwZRo}SIl3qH zR3y6m)T>b*qBu0_LJQVIg=^R{rBOyjC zF)HZAe*;Q5Eup$h`!h&F`vK$~)Z%(~A(h*^&`VrRShW{zuXPoAxf*?ctHq5Fe;=~o z8>%>$J``3hMlI+E*ZNCGaE$Lma(G{r;qz!gZy9ExDXhMP${G}VHR}bNgC69Y8Qv;9 z>E`c5apAnQFJjA>tfe~rz-qJzo`>A_r0bqRCD}KkVJ$1DF0r~EiC;dza5$AV zT_{<3Ug7*#RdFu+k!$~B_ZDfv#mpx z;ZoZjDC?T^Fl<4Io>->I7LzGDmpiLC7iZD#M_J`lP)?!rVVaC4>wF4Haw{eHT*&n+ zG~DG_;_;d?s4DX5!g*I(DDx;(`aP=WpFs1ImECA@f7)|=dr$?XC%sErJ+qO*&3DmP zq7^x<2W1>;PPq)lRXgyzgM+BNHivju-SOy!y$p#~UZlGDdG`VzMT^J*49_`yKdMPr z5?AF>;`UMCOK3rfO}3gtNz0#;ypZKl&SE(VuNIN+B;k3eW3aTWnnz7VrxDL0>!l0D ze@{{VFz!R8tr=+_B(ipA6pqIwbxI$OwP=WE)E68ji58-A>uM^GEzcv%eH)r!^EMRg zy8ZDgc@k?;i|(6HZX#9=K+oc%fph6cA>oav>^gm9zoxEqp|Z5k3)qVm+@7=#GKrZ; z+wF_9SD{2!40?Rf#h!`es7on-_@6~CSuDp}>0D-^T*s{_gsDc0{|tKA_L1y845FU) z+X~lf4)N6UlQ;^6D8BIJK8AA^v7Ac=UE5pn8>MB)a7Ag9a;WL%NzZ}rL)rBhR@q`Q zC^2>`r z8RB&#ugr~>EA;}dBvQ|74!WqND_0&_|FenDnr2WOy@YZPU^6NK#dgfqoYQ2~@9-~3 zO;*irMm~4{QQ&h(q|!sAmM4J&P;6i7k>*j{e|n_nG#BX(d=l&B$diuhxN~UL3R(ZJ z5=ZP`$^?`|^I6K3=p~BkLf1eJC1l@(YV%J}+1k6Gb*NhN7Ah;`wgCR+=Iku zQ%C&mjiZb3`?Qw`z3JIVFyf2-ml5HLRp4Y)CMta~29bznCh@t5wK4_?f!>Yokxy*m zezu`n^oOae_-h4Rh<6iyYq|_gC64hP&qc{rpGUotI=xf%aBp*kgZT*MvB^Fp5V@5& z=DHO#86|2_(OgBXmoC&3?TfMY5^sz( z86~%TEub5bXAnzis8LKrdjCU+W3o^q$)Sd(wfJ*XUn8=Zy6CviPdM&tNO@z?gGjdi zG1e?ING0|N<+1+&3R&9K`gbz3(Eu7>MPN0`1;kkKnTeX`e3hJ)Xn{!OxVuo9>?zNI z?M5@=VzvIC#oryc5hcr7HS2AJNwTJWDCZMP2V*fAB%k+9)#^vG`&nrm*ny}k&6iz$ z6b+4tG4_8Q>I3i%DE&dHy3vTI zjg-Ggdx%%FJP~!o`C|WPkv6{FWB*PjhjbB7QvTe=>;<^V+P-}?`cS#BsmFaFij{q_ z|6|12wUj}1{|E5b{lAA=NR9SpCbFiXew8;9rx!34B`ba2%UVV_UvnfcX%4kbo=myh z(TBD?dW`gEzm+l(t^P+*?&5Djn(<9(AEeQ6o)$_t6llXb`a75tNq)}xmE zs=a_(POuBT;HP+g!5%bg?=i~bleC$PT)HDEU!1m~0gx8^cOK89O+MCpK06p`24eIA zl8$>W%3(C*xDQ72%1Q@k~n7w<*Zzn+_X)QgG8`oGHa*;bTQ-I(@48mX}z4MJV-`D`A_tj9RV z!c_#G^n5nAaNKpx1u z$W?ONyU~l}i~V<_ooOCT`zm;tggU5>@O-u%_&!qq#g?-$(qShu3U01NF$bdAh%r_K zUP8Hm^(DuhL8`z@7-bG)E`IBuM=$=##25P)TmR6kKdbv2rA$L3w|!ds_0(8jZz4UY z_1?E(>;^_L*}9A5y~;jEoU#8T;Bx$`zo)T&f5T4}jYWGLzsl|=8mzJ##c?lSxc{a! z7jO$B+}$`y^B-&7KZ{g)zeXH{GV6I{O=HakOa=ZQelOrDGOF<9o`2$4mdt}F0Y1nQPqZ_sf&El%lif47$7&Y%prZmTEdGvXqPhS`Sd>o*|-85^2Vgp=Ukp+X7VY5sj3e@lqd`ezHr6)J<=ipBm$?Mwmw9e+%{5s7SKOej|hh2I@I zZWsH9ru|$_ys`h~)FJs{7)7}H`ZD~6<=e#R1%S3a_l3i5_-&a%%oI+h6*K<}k$2)N ze|!(^3m4mQ8?C_wY ziqTCoS_4;FUWz}a{x)%jmszv{&JxOp;JQILFUtiSNLcg#I8xWesQF)jzw9x{C?t@E zQA7{P_4S%nc1>auYKITyFy8Nu+fDinY5xB&@y7m1rJ7i8jL}*o3C#MDynHV4g_#+K zhvE7v8MmQ1nH)w~^ZyX)tc#Ha$UE^#He)T*7_EuRtcR@Wdx*0~U=nZ{YIpWY<1g(( z8N*X3x0ZW=-=J2=1JH_+Dg3>(!+{yd!XHNY%DWY;rp zt-?!)Z@P2__#=9Uk1hFZI`HN$w9&wJ;8p9CEIo*zu zXA??3&k<)HAnAOb$)XJqVqCduJ(=Z5$h0}_gE88c7f~3nEbRlS1ABpcb10$qYT|72 zsfGcxh+U5cJNBi0Kt@}$9la~ZA}=7e@VFWVfCqr9b0}NhgG4i9QLK=mylmivK|?A2 zp!j9+Ka3x6c= zJ~aM#KFY55qm{yuM=#y}6fgb|n%cS-x%v;FZOI-ioS0!WgAD4Ny%4=KucW*p6&rc9 ivFQCs_4_+u*Z&8_p#-sm0ms$=0000 + + + + + \ No newline at end of file diff --git a/src/Angor/Avalonia/AngorApp/Common/SuccessView.axaml.cs b/src/Angor/Avalonia/AngorApp/Common/SuccessView.axaml.cs new file mode 100644 index 00000000..0dcf5931 --- /dev/null +++ b/src/Angor/Avalonia/AngorApp/Common/SuccessView.axaml.cs @@ -0,0 +1,13 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; + +namespace AngorApp.Common; + +public partial class SuccessView : UserControl +{ + public SuccessView() + { + InitializeComponent(); + } +} \ No newline at end of file diff --git a/src/Angor/Avalonia/AngorApp/Common/SuccessViewModel.cs b/src/Angor/Avalonia/AngorApp/Common/SuccessViewModel.cs new file mode 100644 index 00000000..d2369906 --- /dev/null +++ b/src/Angor/Avalonia/AngorApp/Common/SuccessViewModel.cs @@ -0,0 +1,18 @@ +using System.Reactive.Linq; +using Zafiro.Avalonia.Controls.Wizards.Builder; + +namespace AngorApp.Common; + +public class SuccessViewModel : IStep +{ + public string Message { get; } + + public SuccessViewModel(string message) + { + Message = message; + } + + public IObservable IsValid => Observable.Return(false); + public IObservable IsBusy => Observable.Return(false); + public bool AutoAdvance => false; +} \ No newline at end of file diff --git a/src/Angor/Avalonia/AngorApp/CompositionRoot.cs b/src/Angor/Avalonia/AngorApp/CompositionRoot.cs index 1037c53e..8b13c5e2 100644 --- a/src/Angor/Avalonia/AngorApp/CompositionRoot.cs +++ b/src/Angor/Avalonia/AngorApp/CompositionRoot.cs @@ -6,6 +6,11 @@ using AngorApp.Sections.Shell; using AngorApp.Sections.Wallet; using AngorApp.Services; +using Avalonia.Controls.Notifications; +using Zafiro.Avalonia.Dialogs; +using Zafiro.Avalonia.Dialogs.SizingAlgorithms; +using Zafiro.Avalonia.Notifications; +using Zafiro.Avalonia.Services; using Separator = AngorApp.Sections.Shell.Separator; namespace AngorApp; @@ -16,21 +21,27 @@ public static MainViewModel CreateMainViewModel(Control control) { var topLevel = TopLevel.GetTopLevel(control); var launcher = new LauncherService(topLevel!.Launcher); - var uiServices = new UIServices(launcher); - + var uiServices = new UIServices( + launcher, + new DesktopDialog(algorithm: new AlternateSizingAlgorithm()), + new NotificationService(new WindowNotificationManager(topLevel) + { + Position = NotificationPosition.BottomRight, + })); + IEnumerable sections = [ new Section("Home", new HomeViewModel(), "svg:/Assets/angor-icon.svg"), new Separator(), new Section("Wallet", new WalletViewModel(), "fa-wallet"), - new Section("Browse", new NavigationViewModel(navigator => new BrowseViewModel(navigator, uiServices)), "fa-magnifying-glass"), + new Section("Browse", new NavigationViewModel(navigator => new BrowseViewModel(() => new WalletDesign(), navigator, uiServices)), "fa-magnifying-glass"), new Section("Portfolio", new PortfolioViewModel(), "fa-hand-holding-dollar"), new Section("Founder", new FounderViewModel(), "fa-money-bills"), new Separator(), new Section("Settings", new WalletViewModel(), "fa-gear"), - new CommandSection("Angor Hub", ReactiveCommand.CreateFromTask(() => uiServices.LauncherService.Launch(new Uri("https://www.angor.io"))) , "fa-magnifying-glass") { IsPrimary = false } + new CommandSection("Angor Hub", ReactiveCommand.CreateFromTask(() => uiServices.LauncherService.LaunchUri(new Uri("https://www.angor.io"))), "fa-magnifying-glass") { IsPrimary = false } ]; - + return new MainViewModel(sections, uiServices); } } \ No newline at end of file diff --git a/src/Angor/Avalonia/AngorApp/Controls/Dialog.axaml b/src/Angor/Avalonia/AngorApp/Controls/Dialog.axaml new file mode 100644 index 00000000..bdcbdaf1 --- /dev/null +++ b/src/Angor/Avalonia/AngorApp/Controls/Dialog.axaml @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Angor/Avalonia/AngorApp/Controls/Frame.axaml b/src/Angor/Avalonia/AngorApp/Controls/Frame.axaml index f4adffbc..42eeab08 100644 --- a/src/Angor/Avalonia/AngorApp/Controls/Frame.axaml +++ b/src/Angor/Avalonia/AngorApp/Controls/Frame.axaml @@ -2,24 +2,26 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:navigation="clr-namespace:Zafiro.Avalonia.Controls.Navigation;assembly=Zafiro.Avalonia" xmlns:avalonia="https://github.com/projektanker/icons.avalonia"> - + - + + + + - - + \ No newline at end of file diff --git a/src/Angor/Avalonia/AngorApp/Controls/Header.axaml b/src/Angor/Avalonia/AngorApp/Controls/Header.axaml index 583f3602..b7a2754c 100644 --- a/src/Angor/Avalonia/AngorApp/Controls/Header.axaml +++ b/src/Angor/Avalonia/AngorApp/Controls/Header.axaml @@ -7,7 +7,7 @@ - + diff --git a/src/Angor/Avalonia/AngorApp/Controls/MiscConverters.cs b/src/Angor/Avalonia/AngorApp/Controls/MiscConverters.cs index 20bad5b3..7f8d4d98 100644 --- a/src/Angor/Avalonia/AngorApp/Controls/MiscConverters.cs +++ b/src/Angor/Avalonia/AngorApp/Controls/MiscConverters.cs @@ -35,9 +35,21 @@ public static class MiscConverters public static readonly FuncValueConverter IsActivatable = new(sectionBase => sectionBase is not Separator); public static readonly FuncValueConverter IsPrimaryToDock = new(isPrimary => isPrimary ? Dock.Top : Dock.Bottom); + public static readonly FuncValueConverter TimeLeft = new(offset => { - Humanizer.Configuration.Configurator.DateTimeHumanizeStrategy = new DefaultDateTimeHumanizeStrategy(); return offset.Humanize(dateToCompareAgainst: DateTimeOffset.Now); }); + + public static readonly FuncValueConverter HumanizeTimeSpan = new(offset => offset.Humanize()); + + public static readonly FuncValueConverter BoolToOpacity = new(b => b ? 1 : 0); + + public static FuncValueConverter HubProfile = new((value) => + { + return "https://hub.angor.io/profile/" + value; + }); + + public static string BigBtcFormat = "{0} BTC"; + public static string AmountBtcFormat = "0.0000 0000 BTC"; } \ No newline at end of file diff --git a/src/Angor/Avalonia/AngorApp/Controls/OptionDesign.cs b/src/Angor/Avalonia/AngorApp/Controls/OptionDesign.cs new file mode 100644 index 00000000..a87a9f9c --- /dev/null +++ b/src/Angor/Avalonia/AngorApp/Controls/OptionDesign.cs @@ -0,0 +1,14 @@ +using System.Reactive.Linq; +using Zafiro.Avalonia.Commands; +using Zafiro.Avalonia.Dialogs; + +namespace AngorApp.Controls; + +public class OptionDesign : IOption +{ + public string Title { get; set; } + public IEnhancedCommand Command { get; } + public bool IsDefault { get; set; } + public bool IsCancel { get; set; } + public IObservable IsVisible { get; } = Observable.Return(true); +} \ No newline at end of file diff --git a/src/Angor/Avalonia/AngorApp/Icons.axaml b/src/Angor/Avalonia/AngorApp/Icons.axaml new file mode 100644 index 00000000..893cd19a --- /dev/null +++ b/src/Angor/Avalonia/AngorApp/Icons.axaml @@ -0,0 +1,15 @@ + + + + + + + + + + + m 13.421875,65.416016 c -0.129476,0 -0.233035,0.08716 -0.294922,0.167968 -0.06189,0.08081 -0.112666,0.174677 -0.179687,0.294922 l -0.03516,0.06055 c -0.0381,0.06833 -0.04782,0.07556 -0.0332,0.06445 0.01463,-0.0111 0.0095,-0.005 -0.06445,0.01172 l -0.06836,0.01563 c -0.130159,0.02945 -0.229956,0.05074 -0.324219,0.08789 -0.09426,0.03715 -0.20494,0.114609 -0.242187,0.234375 -0.03724,0.119766 0.0063,0.243864 0.06055,0.330078 0.05427,0.08621 0.12416,0.165765 0.212891,0.269531 L 12.5,67.005859 c 0.05044,0.05899 0.05128,0.06884 0.04687,0.05469 -0.0044,-0.01423 -2.06e-4,-0.0026 -0.0078,0.07617 v 0.002 l -0.0059,0.07031 c -0.01342,0.138432 -0.02603,0.245556 -0.02148,0.347657 0.0046,0.1021 0.03685,0.22935 0.138672,0.30664 0.101815,0.07729 0.240539,0.07282 0.33789,0.04492 0.09735,-0.02789 0.190635,-0.0728 0.3125,-0.128906 l 0.0625,-0.0293 c 0.06928,-0.0319 0.07939,-0.0293 0.05859,-0.0293 -0.02084,0 -0.01266,-0.0026 0.05664,0.0293 l 0.06445,0.0293 c 0.121857,0.05609 0.215158,0.101011 0.3125,0.128906 0.09734,0.0279 0.234115,0.03237 0.335937,-0.04492 0.101841,-0.07728 0.134127,-0.204535 0.138672,-0.30664 0.0045,-0.102105 -0.0061,-0.209232 -0.01953,-0.347657 l -0.0078,-0.07031 c -0.0076,-0.0788 -0.0034,-0.09238 -0.0078,-0.07813 -0.0044,0.01423 -0.0016,0.0043 0.04883,-0.05469 l 0.04492,-0.05273 c 0.08872,-0.103764 0.158618,-0.183317 0.212891,-0.269531 0.05427,-0.08621 0.09976,-0.210309 0.0625,-0.330078 -0.03723,-0.119774 -0.147925,-0.197225 -0.242188,-0.234375 -0.09426,-0.03715 -0.196009,-0.05844 -0.326172,-0.08789 l -0.06641,-0.01563 c -0.07397,-0.01675 -0.07911,-0.02284 -0.06445,-0.01172 0.01465,0.01112 0.0049,0.0039 -0.0332,-0.06445 l -0.03516,-0.06055 c -0.06702,-0.120245 -0.1178,-0.21411 -0.179687,-0.294922 -0.06189,-0.08081 -0.165446,-0.167968 -0.294922,-0.167968 z m 0,0.441406 c 0.03077,0.04492 0.0689,0.110687 0.126953,0.214844 l 0.03516,0.06055 c 0.0381,0.06834 0.0666,0.131286 0.140625,0.1875 0.07408,0.05623 0.142867,0.0653 0.216797,0.08203 l 0.06641,0.01563 c 0.121695,0.02753 0.203141,0.0496 0.25,0.06641 -0.02879,0.04352 -0.08556,0.112274 -0.169922,0.210937 l -0.04687,0.05273 c -0.05042,0.05897 -0.09792,0.10811 -0.125,0.195312 -0.02714,0.08724 -0.01538,0.153838 -0.0078,0.232422 l 0.0078,0.07227 c 0.01215,0.125419 0.01596,0.208503 0.01563,0.263672 -0.04886,-0.01696 -0.11655,-0.04491 -0.222657,-0.09375 l -0.06445,-0.0293 c -0.06924,-0.03186 -0.128424,-0.06641 -0.222656,-0.06641 -0.09419,0 -0.15535,0.03452 -0.224609,0.06641 l -0.0625,0.0293 c -0.106891,0.04921 -0.175878,0.07695 -0.22461,0.09375 -3.4e-4,-0.05517 0.0054,-0.138254 0.01758,-0.263672 l 0.0078,-0.07227 c 0.0076,-0.07862 0.0193,-0.145221 -0.0078,-0.232422 -0.0271,-0.08713 -0.07653,-0.136346 -0.126953,-0.195312 l -0.04492,-0.05273 c -0.08439,-0.09869 -0.143089,-0.167421 -0.171875,-0.210937 0.04686,-0.0168 0.128308,-0.03887 0.25,-0.06641 l 0.06836,-0.01563 c 0.07395,-0.01674 0.142745,-0.02585 0.216797,-0.08203 0.074,-0.0562 0.100567,-0.119152 0.138672,-0.1875 l 0.03516,-0.06055 c 0.05809,-0.104213 0.09814,-0.169934 0.128906,-0.214844 z m 0,-1.765625 c -0.258417,0 -0.485716,0.08267 -0.900391,0.224609 l -0.152343,0.05078 c -0.397747,0.136151 -0.697116,0.238404 -0.917969,0.328125 -0.220853,0.08972 -0.368656,0.148693 -0.472656,0.296875 -0.103062,0.146831 -0.110021,0.305702 -0.123047,0.544922 -0.01303,0.239221 -0.01367,0.557449 -0.01367,0.980469 v 0.417969 c 0,0.795592 0.306118,1.402596 0.701172,1.83789 0.395054,0.435295 0.873418,0.704145 1.242187,0.865235 0.190872,0.08337 0.346574,0.142578 0.636719,0.142578 0.290144,0 0.443903,-0.05921 0.634766,-0.142578 0.368769,-0.16109 0.849084,-0.42994 1.24414,-0.865235 0.395057,-0.435294 0.701172,-1.042297 0.701172,-1.83789 v -0.417969 c 0,-0.42302 -6.46e-4,-0.741249 -0.01367,-0.980469 -0.01303,-0.239219 -0.01999,-0.398091 -0.123047,-0.544922 -0.104,-0.148182 -0.251802,-0.207153 -0.472656,-0.296875 -0.220853,-0.08972 -0.520221,-0.191974 -0.917969,-0.328125 L 14.32227,64.316406 C 13.907584,64.17446 13.680291,64.091797 13.421875,64.091797 Z m 0,0.398437 c 0.17095,0 0.356802,0.05923 0.771484,0.201172 l 0.152344,0.05273 c 0.397748,0.13615 0.69462,0.238305 0.896485,0.320312 0.201864,0.08201 0.302948,0.162121 0.298828,0.15625 -0.0032,-0.0045 0.03884,0.118516 0.05078,0.337891 0.01195,0.219375 0.01172,0.535964 0.01172,0.958984 v 0.417969 c 0,0.696128 -0.254055,1.195818 -0.595703,1.572265 -0.341649,0.376448 -0.774458,0.621276 -1.109375,0.767579 -0.190878,0.08337 -0.227329,0.109375 -0.476563,0.109375 -0.249235,0 -0.285672,-0.026 -0.476562,-0.109375 -0.334917,-0.146302 -0.767729,-0.391132 -1.109375,-0.767579 -0.341647,-0.376446 -0.597657,-0.876137 -0.597657,-1.572265 v -0.417969 c 0,-0.42302 -2.27e-4,-0.73961 0.01172,-0.958984 0.01195,-0.219374 0.05591,-0.34241 0.05273,-0.337891 -0.0041,0.0059 0.09501,-0.07424 0.296875,-0.15625 0.201865,-0.08201 0.500691,-0.184162 0.898438,-0.320312 l 0.150391,-0.05273 c 0.414676,-0.141944 0.602488,-0.201172 0.773437,-0.201172 z + M 3.5,0 A 0.5,0.5 0 0 1 4,0.5 V 1 h 8 V 0.5 a 0.5,0.5 0 0 1 1,0 V 1 h 1 a 2,2 0 0 1 2,2 v 11 a 2,2 0 0 1 -2,2 H 2 A 2,2 0 0 1 0,14 V 3 A 2,2 0 0 1 2,1 H 3 V 0.5 A 0.5,0.5 0 0 1 3.5,0 Z M 1,4 v 10 a 1,1 0 0 0 1,1 h 12 a 1,1 0 0 0 1,-1 V 4 Z m 8,3 a 1,1 0 0 1 1,-1 h 5 V 8 H 10 A 1,1 0 0 1 9,7 Z M 1,9 h 4 a 1,1 0 0 1 0,2 H 1 Z + M 8.9765625 1.9999805 C 6.4444998 1.9999805 4.6443359 2.2267187 3.4355273 3.4355273 C 2.4068046 4.4642501 2.0919554 5.9264143 2.0201953 7.8983203 A 1 1 0 0 0 1.9999805 7.9999805 A 1 1 0 0 0 2.0121094 8.0609766 C 2.0121082 8.0610171 2.0121106 8.0610533 2.0121094 8.0610937 C 2.0035485 8.3550037 1.9999805 8.6600547 1.9999805 8.9765625 L 1.9999805 15.023438 C 1.9999805 17.555481 2.2267219 19.355661 3.4355273 20.564473 C 4.6443326 21.773285 6.4444971 22.00002 8.9765625 22.00002 L 15.023438 22.00002 C 17.555482 22.00002 19.355664 21.773282 20.564473 20.564473 C 21.773282 19.355664 22.00002 17.555483 22.00002 15.023438 L 22.00002 8.9765625 C 22.00002 8.6600543 21.996451 8.355004 21.987891 8.0610937 C 21.987889 8.0610533 21.987892 8.0610171 21.987891 8.0609766 A 1 1 0 0 0 22.00002 7.9999805 A 1 1 0 0 0 21.974004 7.7817773 C 21.893793 5.869971 21.572445 4.4434946 20.564473 3.4355273 C 19.355661 2.2267219 17.555481 1.9999805 15.023438 1.9999805 L 8.9765625 1.9999805 z M 9 4.0000195 L 15.023438 4.0000195 C 17.412593 4.0000195 18.601483 4.3007442 19.150371 4.8496289 C 19.51874 5.2179965 19.772257 5.8857726 19.901191 7.0000195 L 9 7.0000195 L 9 4.0000195 z M 7.0000195 4.0988086 L 7.0000195 7.0000195 L 4.0988086 7.0000195 C 4.2277443 5.8857719 4.4812634 5.2179944 4.8496289 4.8496289 C 5.2179944 4.4812634 5.8857719 4.2277443 7.0000195 4.0988086 z M 4.0000195 9 L 19.99998 9 L 19.99998 15.023438 C 19.99998 17.412591 19.699262 18.60148 19.150371 19.150371 C 18.60148 19.699262 17.412592 19.99998 15.023438 19.99998 L 8.9765625 19.99998 C 6.5873879 19.99998 5.3985135 19.699258 4.8496289 19.150371 C 4.3007442 18.601483 4.0000195 17.412593 4.0000195 15.023438 L 4.0000195 9 z + diff --git a/src/Angor/Avalonia/AngorApp/Sections/Browse/BrowseView.axaml b/src/Angor/Avalonia/AngorApp/Sections/Browse/BrowseView.axaml index 2924815e..4ed2339d 100644 --- a/src/Angor/Avalonia/AngorApp/Sections/Browse/BrowseView.axaml +++ b/src/Angor/Avalonia/AngorApp/Sections/Browse/BrowseView.axaml @@ -17,18 +17,10 @@ - diff --git a/src/Angor/Avalonia/AngorApp/Sections/Browse/BrowseViewModel.cs b/src/Angor/Avalonia/AngorApp/Sections/Browse/BrowseViewModel.cs index 41dfd8b2..7624ef0a 100644 --- a/src/Angor/Avalonia/AngorApp/Sections/Browse/BrowseViewModel.cs +++ b/src/Angor/Avalonia/AngorApp/Sections/Browse/BrowseViewModel.cs @@ -1,16 +1,18 @@ using System.Linq; +using AngorApp.Sections.Wallet; using AngorApp.Services; +using CSharpFunctionalExtensions; using Zafiro.Avalonia.Controls.Navigation; namespace AngorApp.Sections.Browse; public class BrowseViewModel : ReactiveObject, IBrowseViewModel { - public BrowseViewModel(INavigator navigator, UIServices uiServices) + public BrowseViewModel(Func> getWallet, INavigator navigator, UIServices uiServices) { - Projects = SampleData.GetProjects().Select(project => new ProjectViewModel(project, navigator)).ToList(); - - OpenHub = ReactiveCommand.CreateFromTask(() => uiServices.LauncherService.Launch(new Uri("https://www.angor.io"))); + + Projects = SampleData.GetProjects().Select(project => new ProjectViewModel(getWallet, project, navigator, uiServices)).ToList(); + OpenHub = ReactiveCommand.CreateFromTask(() => uiServices.LauncherService.LaunchUri(new Uri("https://www.angor.io"))); } public ReactiveCommand OpenHub { get; set; } diff --git a/src/Angor/Avalonia/AngorApp/Sections/Browse/BrowseViewModelDesign.cs b/src/Angor/Avalonia/AngorApp/Sections/Browse/BrowseViewModelDesign.cs index 910f5b96..a253085a 100644 --- a/src/Angor/Avalonia/AngorApp/Sections/Browse/BrowseViewModelDesign.cs +++ b/src/Angor/Avalonia/AngorApp/Sections/Browse/BrowseViewModelDesign.cs @@ -1,5 +1,10 @@ using System.Linq; -using Zafiro.Avalonia.Controls.Navigation; +using System.Threading.Tasks; +using AngorApp.Sections.Shell; +using AngorApp.Sections.Wallet; +using AngorApp.Services; +using CSharpFunctionalExtensions; +using Zafiro.UI; namespace AngorApp.Sections.Browse; @@ -7,9 +12,17 @@ public class BrowseViewModelDesign : IBrowseViewModel { public BrowseViewModelDesign() { - Projects = SampleData.GetProjects().Select(project => new ProjectViewModel(project, null)).ToList(); + Projects = SampleData.GetProjects().Select(project => new ProjectViewModel(() => new WalletDesign(), project, null, new UIServices(new NoopLauncherService(), new TestDialog(), new TestNotificationService()))).ToList(); } public IReadOnlyCollection Projects { get; set; } public ReactiveCommand OpenHub { get; set; } -} \ No newline at end of file +} + +public class TestNotificationService : INotificationService +{ + public Task Show(string message, Maybe title) + { + return Task.CompletedTask; + } +} diff --git a/src/Angor/Avalonia/AngorApp/Sections/Browse/Details/IProjectDetailsViewModel.cs b/src/Angor/Avalonia/AngorApp/Sections/Browse/Details/IProjectDetailsViewModel.cs index 72f0d202..30ee3789 100644 --- a/src/Angor/Avalonia/AngorApp/Sections/Browse/Details/IProjectDetailsViewModel.cs +++ b/src/Angor/Avalonia/AngorApp/Sections/Browse/Details/IProjectDetailsViewModel.cs @@ -1,12 +1,18 @@ +using System.Windows.Input; + namespace AngorApp.Sections.Browse.Details; -public interface IProjectDetailsViewModel : IProject +public interface IProjectDetailsViewModel { - string Name { get; } - string ShortDescription { get; } object Icon { get; } object Picture { get; } - public IEnumerable Stages { get; } + public ICommand Invest { get; } + public IEnumerable Relays { get; } + public double TotalDays { get; } + public double TotalInvestment { get; } + public double CurrentDays { get; } + public double CurrentInvestment { get; } + public IProject Project { get; } } public class Stage diff --git a/src/Angor/Avalonia/AngorApp/Sections/Browse/Details/Invest/Amount/AmountView.axaml b/src/Angor/Avalonia/AngorApp/Sections/Browse/Details/Invest/Amount/AmountView.axaml new file mode 100644 index 00000000..ebe8aaf4 --- /dev/null +++ b/src/Angor/Avalonia/AngorApp/Sections/Browse/Details/Invest/Amount/AmountView.axaml @@ -0,0 +1,36 @@ + + + + + + + + + + + Here is a small explanation of the project. + + You can view more details about the project + + + + + + + To invest in this project, the founder must sign a recovery agreement. + This agreement ensures that in the event the project does not succeed, you will be able to recover your funds. + This provides a safety net for your investment, giving you peace of mind that your financial contribution is protected. + + + + + + + \ No newline at end of file diff --git a/src/Angor/Avalonia/AngorApp/Sections/Browse/Details/Invest/Amount/AmountView.axaml.cs b/src/Angor/Avalonia/AngorApp/Sections/Browse/Details/Invest/Amount/AmountView.axaml.cs new file mode 100644 index 00000000..9ec2f960 --- /dev/null +++ b/src/Angor/Avalonia/AngorApp/Sections/Browse/Details/Invest/Amount/AmountView.axaml.cs @@ -0,0 +1,9 @@ +namespace AngorApp.Sections.Browse.Details.Invest.Amount; + +public partial class AmountView : UserControl +{ + public AmountView() + { + InitializeComponent(); + } +} \ No newline at end of file diff --git a/src/Angor/Avalonia/AngorApp/Sections/Browse/Details/Invest/Amount/AmountViewModel.cs b/src/Angor/Avalonia/AngorApp/Sections/Browse/Details/Invest/Amount/AmountViewModel.cs new file mode 100644 index 00000000..6369eba7 --- /dev/null +++ b/src/Angor/Avalonia/AngorApp/Sections/Browse/Details/Invest/Amount/AmountViewModel.cs @@ -0,0 +1,26 @@ +using System.Reactive.Linq; +using AngorApp.Sections.Wallet; +using ReactiveUI.SourceGenerators; +using ReactiveUI.Validation.Extensions; +using ReactiveUI.Validation.Helpers; + +namespace AngorApp.Sections.Browse.Details.Invest.Amount; + +public partial class AmountViewModel : ReactiveValidationObject, IAmountViewModel +{ + [Reactive] private decimal? amount; + + public AmountViewModel(IWallet wallet, IProject project) + { + Project = project; + this.ValidationRule(x => x.Amount, this.WhenAnyValue(x => x.Amount).Skip(1), x => x is null or > 0, _ => "Amount must be greater than zero"); + this.ValidationRule(x => x.Amount, this.WhenAnyValue(x => x.Amount).Skip(1), x => x is not null, _ => "Please, specify an amount"); + this.ValidationRule(x => x.Amount, this.WhenAnyValue(x => x.Amount).Skip(1), x => x is null || x <= wallet.Balance, _ => "The amount should be greater than the wallet balance"); + } + + public IProject Project { get; } + + public IObservable IsValid => this.IsValid(); + public IObservable IsBusy => Observable.Return(false); + public bool AutoAdvance => false; +} \ No newline at end of file diff --git a/src/Angor/Avalonia/AngorApp/Sections/Browse/Details/Invest/Amount/IAmountViewModel.cs b/src/Angor/Avalonia/AngorApp/Sections/Browse/Details/Invest/Amount/IAmountViewModel.cs new file mode 100644 index 00000000..ed8ba5ce --- /dev/null +++ b/src/Angor/Avalonia/AngorApp/Sections/Browse/Details/Invest/Amount/IAmountViewModel.cs @@ -0,0 +1,9 @@ +using Zafiro.Avalonia.Controls.Wizards.Builder; + +namespace AngorApp.Sections.Browse.Details.Invest.Amount; + +public interface IAmountViewModel : IStep +{ + public decimal? Amount { get; set; } + IProject Project { get; } +} \ No newline at end of file diff --git a/src/Angor/Avalonia/AngorApp/Sections/Browse/Details/Invest/Amount/InvestViewModelDesign.cs b/src/Angor/Avalonia/AngorApp/Sections/Browse/Details/Invest/Amount/InvestViewModelDesign.cs new file mode 100644 index 00000000..09920983 --- /dev/null +++ b/src/Angor/Avalonia/AngorApp/Sections/Browse/Details/Invest/Amount/InvestViewModelDesign.cs @@ -0,0 +1,14 @@ +using System.Reactive.Linq; +using System.Windows.Input; + +namespace AngorApp.Sections.Browse.Details.Invest.Amount; + +public class AmountViewModelDesign : IAmountViewModel +{ + public ICommand Next { get; } = ReactiveCommand.Create(() => { }); + public decimal? Amount { get; set; } = 0.001m; + public IProject Project { get; } = new ProjectDesign(); + public IObservable IsValid => Observable.Return(true); + public IObservable IsBusy => Observable.Return(false); + public bool AutoAdvance => false; +} \ No newline at end of file diff --git a/src/Angor/Avalonia/AngorApp/Sections/Browse/Details/Invest/TransactionPreview/ITransactionPreview.cs b/src/Angor/Avalonia/AngorApp/Sections/Browse/Details/Invest/TransactionPreview/ITransactionPreview.cs new file mode 100644 index 00000000..c64118b9 --- /dev/null +++ b/src/Angor/Avalonia/AngorApp/Sections/Browse/Details/Invest/TransactionPreview/ITransactionPreview.cs @@ -0,0 +1,15 @@ +using AngorApp.Sections.Wallet; +using CSharpFunctionalExtensions; +using Zafiro.Avalonia.Controls.Wizards.Builder; + +namespace AngorApp.Sections.Browse.Details.Invest.TransactionPreview; + +public interface ITransactionPreviewViewModel : IStep +{ + public ITransaction Transaction { get; } + public IObservable IsBusy { get; } + ReactiveCommand Confirm { get; } + ReactiveCommand CreateTransaction { get; } + public IObservable TransactionConfirmed { get; } + IProject Project { get; } +} \ No newline at end of file diff --git a/src/Angor/Avalonia/AngorApp/Sections/Browse/Details/Invest/TransactionPreview/ITransactionViewModelPreviewDesign.cs b/src/Angor/Avalonia/AngorApp/Sections/Browse/Details/Invest/TransactionPreview/ITransactionViewModelPreviewDesign.cs new file mode 100644 index 00000000..29374224 --- /dev/null +++ b/src/Angor/Avalonia/AngorApp/Sections/Browse/Details/Invest/TransactionPreview/ITransactionViewModelPreviewDesign.cs @@ -0,0 +1,16 @@ +using AngorApp.Sections.Wallet; +using CSharpFunctionalExtensions; + +namespace AngorApp.Sections.Browse.Details.Invest.TransactionPreview; + +public class TransactionPreviewViewModelDesign : ITransactionPreviewViewModel +{ + public ITransaction Transaction { get; set; } + public IObservable IsBusy { get; set; } + public ReactiveCommand Confirm { get; } + public ReactiveCommand CreateTransaction { get; } + public IObservable TransactionConfirmed { get; } + public IProject Project { get; } + public IObservable IsValid { get; } + public bool AutoAdvance => false; +} \ No newline at end of file diff --git a/src/Angor/Avalonia/AngorApp/Sections/Browse/Details/Invest/TransactionPreview/TransactionPreviewView.axaml b/src/Angor/Avalonia/AngorApp/Sections/Browse/Details/Invest/TransactionPreview/TransactionPreviewView.axaml new file mode 100644 index 00000000..1f35aa5d --- /dev/null +++ b/src/Angor/Avalonia/AngorApp/Sections/Browse/Details/Invest/TransactionPreview/TransactionPreviewView.axaml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + This is a preview of the transaction you will send. + + If everything is correct you can confirm it with the button below. + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Angor/Avalonia/AngorApp/Sections/Browse/Details/Invest/TransactionPreview/TransactionPreviewView.axaml.cs b/src/Angor/Avalonia/AngorApp/Sections/Browse/Details/Invest/TransactionPreview/TransactionPreviewView.axaml.cs new file mode 100644 index 00000000..b91d7f02 --- /dev/null +++ b/src/Angor/Avalonia/AngorApp/Sections/Browse/Details/Invest/TransactionPreview/TransactionPreviewView.axaml.cs @@ -0,0 +1,13 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; + +namespace AngorApp.Sections.Browse.Details.Invest.TransactionPreview; + +public partial class TransactionPreviewView : UserControl +{ + public TransactionPreviewView() + { + InitializeComponent(); + } +} \ No newline at end of file diff --git a/src/Angor/Avalonia/AngorApp/Sections/Browse/Details/Invest/TransactionPreview/TransactionPreviewViewModel.cs b/src/Angor/Avalonia/AngorApp/Sections/Browse/Details/Invest/TransactionPreview/TransactionPreviewViewModel.cs new file mode 100644 index 00000000..9c9d2909 --- /dev/null +++ b/src/Angor/Avalonia/AngorApp/Sections/Browse/Details/Invest/TransactionPreview/TransactionPreviewViewModel.cs @@ -0,0 +1,40 @@ +using System.Reactive.Linq; +using AngorApp.Sections.Wallet; +using AngorApp.Services; +using CSharpFunctionalExtensions; +using ReactiveUI.SourceGenerators; +using ReactiveUI.Validation.Helpers; +using Zafiro.CSharpFunctionalExtensions; +using Zafiro.Reactive; +using Zafiro.UI; + +namespace AngorApp.Sections.Browse.Details.Invest.TransactionPreview; + +public partial class TransactionPreviewViewModel : ReactiveValidationObject, ITransactionPreviewViewModel +{ + [ObservableAsProperty] private ITransaction? transaction; + + public TransactionPreviewViewModel(IWallet wallet, IProject project, UIServices services, decimal amount) + { + Project = project; + Amount = amount; + CreateTransaction = ReactiveCommand.CreateFromTask(() => wallet.CreateTransaction(amount, project.BitcoinAddress)); + transactionHelper = CreateTransaction.ToProperty(this, x => x.Transaction); + Confirm = ReactiveCommand.CreateFromTask(() => Transaction!.Broadcast(), this.WhenAnyValue(x => x.Transaction).NotNull()); + TransactionConfirmed = Confirm.Successes().Select(_ => true).StartWith(false); + IsBusy = CreateTransaction.IsExecuting.CombineLatest(Confirm.IsExecuting, (a, b) => a | b); + + Confirm.HandleErrorsWith(services.NotificationService, "Could not confirm transaction"); + + CreateTransaction.Execute().Subscribe(); + } + + public IProject Project { get; } + public decimal Amount { get; } + public ReactiveCommand Confirm { get; } + public IObservable IsBusy { get; } + public ReactiveCommand CreateTransaction { get; } + public IObservable TransactionConfirmed { get; } + public IObservable IsValid => TransactionConfirmed; + public bool AutoAdvance => true; +} \ No newline at end of file diff --git a/src/Angor/Avalonia/AngorApp/Sections/Browse/Details/NostProperties.axaml b/src/Angor/Avalonia/AngorApp/Sections/Browse/Details/NostProperties.axaml new file mode 100644 index 00000000..35093093 --- /dev/null +++ b/src/Angor/Avalonia/AngorApp/Sections/Browse/Details/NostProperties.axaml @@ -0,0 +1,102 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Angor/Avalonia/AngorApp/Sections/Browse/Details/NostProperties.axaml.cs b/src/Angor/Avalonia/AngorApp/Sections/Browse/Details/NostProperties.axaml.cs new file mode 100644 index 00000000..98f3c43d --- /dev/null +++ b/src/Angor/Avalonia/AngorApp/Sections/Browse/Details/NostProperties.axaml.cs @@ -0,0 +1,9 @@ +namespace AngorApp.Sections.Browse.Details; + +public partial class NostProperties : UserControl +{ + public NostProperties() + { + InitializeComponent(); + } +} \ No newline at end of file diff --git a/src/Angor/Avalonia/AngorApp/Sections/Browse/Details/ProjectDetailsView.axaml b/src/Angor/Avalonia/AngorApp/Sections/Browse/Details/ProjectDetailsView.axaml index f658e93e..737fe451 100644 --- a/src/Angor/Avalonia/AngorApp/Sections/Browse/Details/ProjectDetailsView.axaml +++ b/src/Angor/Avalonia/AngorApp/Sections/Browse/Details/ProjectDetailsView.axaml @@ -2,60 +2,34 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - xmlns:details="clr-namespace:AngorApp.Sections.Browse.Details" + xmlns:dt="clr-namespace:AngorApp.Sections.Browse.Details" xmlns:controls="clr-namespace:AngorApp.Controls" - xmlns:a="https://github.com/projektanker/icons.avalonia" - xmlns:z="clr-namespace:Zafiro.Avalonia.Controls.SlimDataGrid;assembly=Zafiro.Avalonia" mc:Ignorable="d" d:DesignWidth="1200" - x:Class="AngorApp.Sections.Browse.Details.ProjectDetailsView" x:DataType="details:IProjectDetailsViewModel" ClipToBounds="False"> + x:Class="AngorApp.Sections.Browse.Details.ProjectDetailsView" x:DataType="dt:IProjectDetailsViewModel"> - + - + - - - - - - PLACEHOLDER - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Angor/Avalonia/AngorApp/Sections/Browse/Details/ProjectDetailsViewModel.cs b/src/Angor/Avalonia/AngorApp/Sections/Browse/Details/ProjectDetailsViewModel.cs index 32f8a8d6..e4f1f369 100644 --- a/src/Angor/Avalonia/AngorApp/Sections/Browse/Details/ProjectDetailsViewModel.cs +++ b/src/Angor/Avalonia/AngorApp/Sections/Browse/Details/ProjectDetailsViewModel.cs @@ -1,10 +1,57 @@ +using System.Threading.Tasks; +using System.Windows.Input; +using AngorApp.Common; +using AngorApp.Sections.Browse.Details.Invest.Amount; +using AngorApp.Sections.Browse.Details.Invest.TransactionPreview; +using AngorApp.Sections.Wallet; +using AngorApp.Services; +using CSharpFunctionalExtensions; +using Zafiro.Avalonia.Controls.Wizards.Builder; +using Zafiro.Avalonia.Dialogs; + namespace AngorApp.Sections.Browse.Details; -public class ProjectDetailsViewModel(Project project) : ReactiveObject, IProjectDetailsViewModel +public class ProjectDetailsViewModel(Func> getWallet, IProject project, UIServices uiServices) : ReactiveObject, IProjectDetailsViewModel { public string Name => project.Name; public string ShortDescription => project.ShortDescription; public object Icon => project.Icon; public object Picture => project.Picture; - public IEnumerable Stages { get; } + + public ICommand Invest { get; } = ReactiveCommand.CreateFromTask(() => + { + var maybeWallet = getWallet(); + return maybeWallet.Match(wallet => DoInvest(wallet, project, uiServices), () => uiServices.NotificationService.Show("You need to create a Wallet before investing", "No wallet")); + }); + + public string NpubKey { get; } = "npub109t62lkxkfs7m4cac0lp0en45ndl3kdcnqm0serd450dravj9lvq3duh5k"; + public string NpubKeyHex { get; } = "7957a57ec6b261edd71dc3fe17e675a4dbf8d9b89836f8646dad1ed1f5922fd8"; + + public IEnumerable Relays { get; } = + [ + new NostrRelayDesign + { + Uri = new Uri("wss://relay.angor.io") + }, + new NostrRelayDesign + { + Uri = new Uri("wss://relay2.angor.io") + } + ]; + + public double TotalDays { get; } = 119; + public double TotalInvestment { get; } = 1.5d; + public double CurrentDays { get; } = 11; + public double CurrentInvestment { get; } = 0.79d; + public IProject Project => project; + + private static async Task DoInvest(IWallet wallet, IProject project, UIServices uiServices) + { + var wizard = WizardBuilder.StartWith(() => new AmountViewModel(wallet, project)) + .Then(viewModel => new TransactionPreviewViewModel(wallet, project, uiServices, viewModel.Amount!.Value)) + .Then(prev => new SuccessViewModel("Transaction confirmed!")) + .Build(); + + await uiServices.Dialog.Show(wizard, @$"Invest in ""{project}""", closeable => wizard.OptionsForCloseable(closeable)); + } } \ No newline at end of file diff --git a/src/Angor/Avalonia/AngorApp/Sections/Browse/Details/ProjectDetailsViewModelDesign.cs b/src/Angor/Avalonia/AngorApp/Sections/Browse/Details/ProjectDetailsViewModelDesign.cs index dab5882c..7e0d92e0 100644 --- a/src/Angor/Avalonia/AngorApp/Sections/Browse/Details/ProjectDetailsViewModelDesign.cs +++ b/src/Angor/Avalonia/AngorApp/Sections/Browse/Details/ProjectDetailsViewModelDesign.cs @@ -1,3 +1,5 @@ +using System.Windows.Input; + namespace AngorApp.Sections.Browse.Details; public class ProjectDetailsViewModelDesign : IProjectDetailsViewModel @@ -18,6 +20,38 @@ public ProjectDetailsViewModelDesign() new() { ReleaseDate = DateTimeOffset.Now.Date.AddDays(1), Amount = new decimal(0.1), Index = 1, Weight = 0.25d }, new() { ReleaseDate = DateTimeOffset.Now.Add(TimeSpan.FromDays(20)), Amount = new decimal(0.4), Index = 2, Weight = 0.25d }, new() { ReleaseDate = DateTimeOffset.Now.Add(TimeSpan.FromDays(40)), Amount = new decimal(0.3), Index = 3, Weight = 0.25d }, - new() { ReleaseDate = DateTimeOffset.Now.Add(TimeSpan.FromDays(60)), Amount = new decimal(0.2), Index = 4, Weight = 0.25d }, + new() { ReleaseDate = DateTimeOffset.Now.Add(TimeSpan.FromDays(60)), Amount = new decimal(0.2), Index = 4, Weight = 0.25d } + ]; + + public ICommand Invest { get; } + public string NpubKey { get; } = "npub109t62lkxkfs7m4cac0lp0en45ndl3kdcnqm0serd450dravj9lvq3duh5k"; + public string NpubKeyHex { get; } = "7957a57ec6b261edd71dc3fe17e675a4dbf8d9b89836f8646dad1ed1f5922fd8"; + + public IEnumerable Relays { get; } = + [ + new NostrRelayDesign + { + Uri = new Uri("wss://relay.angor.io") + }, + new NostrRelayDesign + { + Uri = new Uri("wss://relay2.angor.io") + } ]; + + public double TotalDays { get; } = 119; + public double TotalInvestment { get; } = 1.5d; + public double CurrentDays { get; } = 11; + public double CurrentInvestment { get; } = 0.79d; + public IProject Project { get; set; } = new ProjectDesign(); +} + +public class NostrRelayDesign : INostrRelay +{ + public Uri Uri { get; set; } +} + +public interface INostrRelay +{ + public Uri Uri { get; } } \ No newline at end of file diff --git a/src/Angor/Avalonia/AngorApp/Sections/Browse/Details/ProjectSummary.axaml b/src/Angor/Avalonia/AngorApp/Sections/Browse/Details/ProjectSummary.axaml new file mode 100644 index 00000000..76006041 --- /dev/null +++ b/src/Angor/Avalonia/AngorApp/Sections/Browse/Details/ProjectSummary.axaml @@ -0,0 +1,122 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Target amount: + + + + + + + + + + + + + Penalty duration: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Angor/Avalonia/AngorApp/Sections/Browse/Details/ProjectSummary.axaml.cs b/src/Angor/Avalonia/AngorApp/Sections/Browse/Details/ProjectSummary.axaml.cs new file mode 100644 index 00000000..3406d1aa --- /dev/null +++ b/src/Angor/Avalonia/AngorApp/Sections/Browse/Details/ProjectSummary.axaml.cs @@ -0,0 +1,13 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; + +namespace AngorApp.Sections.Browse.Details; + +public partial class ProjectSummary : UserControl +{ + public ProjectSummary() + { + InitializeComponent(); + } +} \ No newline at end of file diff --git a/src/Angor/Avalonia/AngorApp/Sections/Browse/Details/Stages.axaml b/src/Angor/Avalonia/AngorApp/Sections/Browse/Details/Stages.axaml new file mode 100644 index 00000000..6bfb520d --- /dev/null +++ b/src/Angor/Avalonia/AngorApp/Sections/Browse/Details/Stages.axaml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Angor/Avalonia/AngorApp/Sections/Browse/Details/Stages.axaml.cs b/src/Angor/Avalonia/AngorApp/Sections/Browse/Details/Stages.axaml.cs new file mode 100644 index 00000000..2738e31d --- /dev/null +++ b/src/Angor/Avalonia/AngorApp/Sections/Browse/Details/Stages.axaml.cs @@ -0,0 +1,13 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; + +namespace AngorApp.Sections.Browse.Details; + +public partial class Stages : UserControl +{ + public Stages() + { + InitializeComponent(); + } +} \ No newline at end of file diff --git a/src/Angor/Avalonia/AngorApp/Sections/Browse/IProject.cs b/src/Angor/Avalonia/AngorApp/Sections/Browse/IProject.cs index 88177999..851e1dc4 100644 --- a/src/Angor/Avalonia/AngorApp/Sections/Browse/IProject.cs +++ b/src/Angor/Avalonia/AngorApp/Sections/Browse/IProject.cs @@ -2,17 +2,58 @@ namespace AngorApp.Sections.Browse; public interface IProject { + public string Id { get; set; } public string Name { get; } - public object Picture { get; } - public object Icon { get; } + public Uri Picture { get; } + public Uri Icon { get; } public string ShortDescription { get; } + string BitcoinAddress { get; } + public decimal TargetAmount { get; } + public DateOnly StartingDate { get; } + IEnumerable Stages { get; } + public string NpubKey { get; } + public string NpubKeyHex { get; } + public TimeSpan PenaltyDuration { get; } } public class ProjectDesign : IProject { - public Uri? Uri { get; set; } - public string Name { get; set; } - public object Picture { get; set; } - public object Icon { get; set; } - public string ShortDescription { get; set; } + public string Id { get; set; } = "angor1qmd8kazm8uzk7s0gddf4amjx4mzj3n5wzgn3mde"; + public string Name { get; set; } = "Test Project"; + public Uri Picture { get; set; } = new Uri("https://images.pexels.com/photos/998641/pexels-photo-998641.jpeg?auto=compress&cs=tinysrgb&w=600"); + public Uri Icon { get; set; } = new Uri("https://images.pexels.com/photos/998641/pexels-photo-998641.jpeg?auto=compress&cs=tinysrgb&w=600"); + public string ShortDescription { get; set; } = "Short description of the project"; + public string BitcoinAddress { get; } = "some address"; + public decimal TargetAmount { get; } = 50m; + public DateOnly StartingDate { get; } = DateOnly.FromDateTime(DateTime.Now); + + public IEnumerable Stages { get; } = + [ + new StageDesign() { ReleaseDate = DateOnly.FromDateTime(DateTime.Today), Amount = new decimal(0.1), Index = 1, Weight = 0.25d }, + new StageDesign() { ReleaseDate = DateOnly.FromDateTime(DateTime.Today).AddDays(20), Amount = new decimal(0.4), Index = 2, Weight = 0.25d }, + new StageDesign() { ReleaseDate = DateOnly.FromDateTime(DateTime.Today).AddDays(40), Amount = new decimal(0.3), Index = 3, Weight = 0.25d }, + new StageDesign() { ReleaseDate = DateOnly.FromDateTime(DateTime.Today).AddDays(60), Amount = new decimal(0.2), Index = 4, Weight = 0.25d } + ]; + + public string NpubKey { get; } = "npub17a0glwdvr5wjyjdh5eu4xmh4swtaqrmhcgss22unvr6p3spyyq7qeh4kaz"; + public string NpubKeyHex { get; } = "f75e8fb9ac1d1d2249b7a679536ef58397d00f77c221052b9360f418c024203c"; + public TimeSpan PenaltyDuration { get; } = TimeSpan.FromDays(90); + + public override string ToString() => Name; +} + +public class StageDesign : IStage +{ + public DateOnly ReleaseDate { get; set; } + public decimal Amount { get; set; } + public int Index { get; set; } + public double Weight { get; set; } +} + +public interface IStage +{ + DateOnly ReleaseDate { get; } + decimal Amount { get; } + int Index { get; } + double Weight { get; } } \ No newline at end of file diff --git a/src/Angor/Avalonia/AngorApp/Sections/Browse/Project.cs b/src/Angor/Avalonia/AngorApp/Sections/Browse/Project.cs deleted file mode 100644 index 9bb23e57..00000000 --- a/src/Angor/Avalonia/AngorApp/Sections/Browse/Project.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace AngorApp.Sections.Browse; - -public class Project(string name) -{ - public string Name { get; } = name; - public Uri Picture { get; init; } - public Uri Icon { get; set; } - public string ShortDescription { get; set; } -} \ No newline at end of file diff --git a/src/Angor/Avalonia/AngorApp/Sections/Browse/ProjectViewModel.cs b/src/Angor/Avalonia/AngorApp/Sections/Browse/ProjectViewModel.cs index 8f346c0d..8248229e 100644 --- a/src/Angor/Avalonia/AngorApp/Sections/Browse/ProjectViewModel.cs +++ b/src/Angor/Avalonia/AngorApp/Sections/Browse/ProjectViewModel.cs @@ -1,16 +1,19 @@ using AngorApp.Sections.Browse.Details; +using AngorApp.Sections.Wallet; +using AngorApp.Services; +using CSharpFunctionalExtensions; using Zafiro.Avalonia.Controls.Navigation; namespace AngorApp.Sections.Browse; public class ProjectViewModel : ReactiveObject { - private readonly Project project; + private readonly IProject project; - public ProjectViewModel(Project project, INavigator navigator) + public ProjectViewModel(Func> getWallet, IProject project, INavigator navigator, UIServices uiServices) { this.project = project; - GoToDetails = ReactiveCommand.Create(() => navigator.Go(() => new ProjectDetailsViewModel(project))); + GoToDetails = ReactiveCommand.Create(() => navigator.Go(() => new ProjectDetailsViewModel(getWallet, project, uiServices))); } public string Name => project.Name; diff --git a/src/Angor/Avalonia/AngorApp/Sections/Browse/SampleData.cs b/src/Angor/Avalonia/AngorApp/Sections/Browse/SampleData.cs index db1b3930..a8968617 100644 --- a/src/Angor/Avalonia/AngorApp/Sections/Browse/SampleData.cs +++ b/src/Angor/Avalonia/AngorApp/Sections/Browse/SampleData.cs @@ -1,46 +1,57 @@ +using System.Linq; + namespace AngorApp.Sections.Browse; public static class SampleData { - public static IEnumerable GetProjects() + public static IEnumerable GetProjects() { - IEnumerable projects = + IEnumerable projects = [ - new("GHJ-TGH-56") + new ProjectDesign() { + Name = "GHJ-TGH-56", Picture = new Uri("https://img.freepik.com/premium-photo/shoot-blue-nebula-with-purple-parts-deep-space-colorful-generative-ai-aig15_31965-139737.jpg"), - Icon = new Uri("https://img.freepik.com/premium-photo/shoot-blue-nebula-with-purple-parts-deep-space-colorful-generative-ai-aig15_31965-139737.jpg") + Icon = new Uri("https://img.freepik.com/premium-photo/shoot-blue-nebula-with-purple-parts-deep-space-colorful-generative-ai-aig15_31965-139737.jpg"), + ShortDescription = "Short Description", + Id = "Id" }, - new("Visit a black hole") + new() { + Name = "Visit a black hole", Picture = new Uri("https://img.freepik.com/free-photo/magical-fantasy-black-hole-illustration_23-2151678388.jpg?t=st=1733787946~exp=1733791546~hmac=0b93c5bbb4a6e522b8e61dc3f72bf4e7c2714f5f40d4b982493011cca8a9d97e&w=1380"), Icon = new Uri("https://img.freepik.com/free-photo/magical-fantasy-black-hole-illustration_23-2151678388.jpg?t=st=1733787946~exp=1733791546~hmac=0b93c5bbb4a6e522b8e61dc3f72bf4e7c2714f5f40d4b982493011cca8a9d97e&w=1380") }, - new("Making investments great again") + new() { + Name = "Making investments great again", ShortDescription = "Decentralize everything", Picture = new Uri("https://img.freepik.com/free-photo/minimalistic-still-life-assortment-with-cryptocurrency_23-2149102095.jpg?t=st=1733788307~exp=1733791907~hmac=baf06e4f989aa3bdf3cf1a94c44ad9f72b4595e3a897b9257cb26a8b405e4a00&w=1380"), Icon = new Uri("https://img.freepik.com/free-vector/digital-bitcoin-currency-symbol-vector-design_1017-10540.jpg?t=st=1733788336~exp=1733791936~hmac=4e10d9eaff66dfa94ca098207656c448b64369c61fb073438c4361e2c32e9f33&w=826") }, - new("Space exploration") + new() { + Name = "Space exploration", Picture = new Uri("https://images.pexels.com/photos/998641/pexels-photo-998641.jpeg?auto=compress&cs=tinysrgb&w=600"), Icon = new Uri("https://images.pexels.com/photos/998641/pexels-photo-998641.jpeg?auto=compress&cs=tinysrgb&w=600") }, - new("Ariton") + new() { + Name = "Ariton", Picture = new Uri("https://ariton.app/assets/ariton-social.png"), ShortDescription = "Community Super App", Icon = new Uri("https://ariton.app/assets/community.webp") }, - new("Matrix 5") + new() { + Name = "Matrix 5", Picture = new Uri("https://m.primal.net/KrhZ.jpg"), ShortDescription = "Matrix 5 Project", Icon = new Uri("https://pfp.nostr.build/5828e07a01a89d6059e85a00ca57680a1b835f2ad197afb2798ad8c7e175cf65.jpg") }, - new("Bitcoin festival") + new() { + Name = "Bitcoin festival", Picture = new Uri("https://unchainedcrypto.com/wp-content/uploads/2023/10/bitcoin-hashrate.jpg"), Icon = new Uri("https://unchainedcrypto.com/wp-content/uploads/2023/10/bitcoin-hashrate.jpg") }, diff --git a/src/Angor/Avalonia/AngorApp/Sections/Founder/FounderView.axaml b/src/Angor/Avalonia/AngorApp/Sections/Founder/FounderView.axaml index d189621e..68f628c2 100644 --- a/src/Angor/Avalonia/AngorApp/Sections/Founder/FounderView.axaml +++ b/src/Angor/Avalonia/AngorApp/Sections/Founder/FounderView.axaml @@ -25,24 +25,19 @@ - + + - + - CREATE PROJECT + + CREATE PROJECT @@ -52,7 +47,7 @@ - + diff --git a/src/Angor/Avalonia/AngorApp/Sections/Founder/FounderViewModel.cs b/src/Angor/Avalonia/AngorApp/Sections/Founder/FounderViewModel.cs index 538274ac..440e2eda 100644 --- a/src/Angor/Avalonia/AngorApp/Sections/Founder/FounderViewModel.cs +++ b/src/Angor/Avalonia/AngorApp/Sections/Founder/FounderViewModel.cs @@ -1,3 +1,5 @@ +using System.Collections.ObjectModel; +using System.Linq; using AngorApp.Sections.Browse; namespace AngorApp.Sections.Founder; @@ -6,13 +8,8 @@ public class FounderViewModel : ReactiveObject, IFounderViewModel { public FounderViewModel() { - Projects = - [ - new Project("Ariton") { Picture = new Uri("https://ariton.app/assets/ariton-social.png") , ShortDescription = "Community Super App"}, - new Project("Matrix 5") { Picture = new Uri("https://m.primal.net/KrhZ.jpg"), ShortDescription = "Matrix 5 Project" }, - new Project("Bitcoin festival") { Picture = new Uri("https://unchainedcrypto.com/wp-content/uploads/2023/10/bitcoin-hashrate.jpg") }, - ]; + Projects = new ReadOnlyCollection(SampleData.GetProjects().ToList()); } - public IReadOnlyCollection Projects { get; set; } + public IReadOnlyCollection Projects { get; set; } } \ No newline at end of file diff --git a/src/Angor/Avalonia/AngorApp/Sections/Portfolio/PorfolioView.axaml b/src/Angor/Avalonia/AngorApp/Sections/Portfolio/PorfolioView.axaml index 384d61ac..c5b09125 100644 --- a/src/Angor/Avalonia/AngorApp/Sections/Portfolio/PorfolioView.axaml +++ b/src/Angor/Avalonia/AngorApp/Sections/Portfolio/PorfolioView.axaml @@ -24,18 +24,11 @@ - + - + @@ -46,14 +39,14 @@ - + - + @@ -69,8 +62,8 @@ - - + + diff --git a/src/Angor/Avalonia/AngorApp/Sections/Shell/MainView.axaml b/src/Angor/Avalonia/AngorApp/Sections/Shell/MainView.axaml index 5f4cab55..1cb2c7cd 100644 --- a/src/Angor/Avalonia/AngorApp/Sections/Shell/MainView.axaml +++ b/src/Angor/Avalonia/AngorApp/Sections/Shell/MainView.axaml @@ -3,12 +3,13 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:shell="clr-namespace:AngorApp.Sections.Shell" + xmlns:behaviors="clr-namespace:Zafiro.Avalonia.Behaviors;assembly=Zafiro.Avalonia" mc:Ignorable="d" d:DesignWidth="1000" d:DesignHeight="700" x:Class="AngorApp.Sections.Shell.MainView" x:DataType="shell:MainViewModel"> - + @@ -16,6 +17,9 @@ + + + diff --git a/src/Angor/Avalonia/AngorApp/Sections/Shell/MainViewModel.cs b/src/Angor/Avalonia/AngorApp/Sections/Shell/MainViewModel.cs index 41ea68a6..484cc2f5 100644 --- a/src/Angor/Avalonia/AngorApp/Sections/Shell/MainViewModel.cs +++ b/src/Angor/Avalonia/AngorApp/Sections/Shell/MainViewModel.cs @@ -12,7 +12,7 @@ public MainViewModel(IEnumerable sections, UIServices uiServices) { Sections = sections; SelectedSection = Sections.OfType
().Skip(0).First(); - OpenHub = ReactiveCommand.CreateFromTask(() => uiServices.LauncherService.Launch(new Uri("https://www.angor.io"))); + OpenHub = ReactiveCommand.CreateFromTask(() => uiServices.LauncherService.LaunchUri(new Uri("https://www.angor.io"))); } public ReactiveCommand OpenHub { get; set; } diff --git a/src/Angor/Avalonia/AngorApp/Sections/Shell/MainViewModelDesign.cs b/src/Angor/Avalonia/AngorApp/Sections/Shell/MainViewModelDesign.cs index c09ff836..e17d9e0a 100644 --- a/src/Angor/Avalonia/AngorApp/Sections/Shell/MainViewModelDesign.cs +++ b/src/Angor/Avalonia/AngorApp/Sections/Shell/MainViewModelDesign.cs @@ -2,6 +2,7 @@ using AngorApp.Sections.Home; using AngorApp.Sections.Wallet; using AngorApp.Services; +using CSharpFunctionalExtensions; using Zafiro.Avalonia.Controls.Navigation; namespace AngorApp.Sections.Shell; @@ -15,7 +16,7 @@ public MainViewModelDesign() new Section("Home", new HomeViewModel(), "svg:/Assets/angor-icon.svg"), new Separator(), new Section("Wallet", new WalletViewModel(), "fa-wallet"), - new Section("Browse", new BrowseViewModel(new Navigator(), new UIServices(new NoopLauncherService())), "fa-magnifying-glass"), + new Section("Browse", new BrowseViewModel(() => new WalletDesign() ,new Navigator(), new UIServices(new NoopLauncherService(), new TestDialog(), new TestNotificationService())), "fa-magnifying-glass"), new Section("Portfolio", new WalletViewModel(), "fa-hand-holding-dollar"), new Section("Founder", new WalletViewModel(), "fa-money-bills"), new Separator(), diff --git a/src/Angor/Avalonia/AngorApp/Sections/Shell/MainWindow.axaml b/src/Angor/Avalonia/AngorApp/Sections/Shell/MainWindow.axaml index 6865b367..af1e1a7e 100644 --- a/src/Angor/Avalonia/AngorApp/Sections/Shell/MainWindow.axaml +++ b/src/Angor/Avalonia/AngorApp/Sections/Shell/MainWindow.axaml @@ -3,10 +3,10 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" - Width="1200" + Width="1400" Height="800" WindowStartupLocation="CenterOwner" x:Class="AngorApp.Sections.Shell.MainWindow" - Icon="/Assets/avalonia-logo.ico" + Icon="/Assets/angor-logo.ico" Title="Angor"> diff --git a/src/Angor/Avalonia/AngorApp/Sections/Shell/TestDialog.cs b/src/Angor/Avalonia/AngorApp/Sections/Shell/TestDialog.cs new file mode 100644 index 00000000..07bbc3d5 --- /dev/null +++ b/src/Angor/Avalonia/AngorApp/Sections/Shell/TestDialog.cs @@ -0,0 +1,12 @@ +using System.Threading.Tasks; +using Zafiro.Avalonia.Dialogs; + +namespace AngorApp.Sections.Shell; + +public class TestDialog : IDialog +{ + public Task Show(object viewModel, string title, Func> optionsFactory) + { + return Task.FromResult(false); + } +} \ No newline at end of file diff --git a/src/Angor/Avalonia/AngorApp/Sections/Wallet/WalletDesign.cs b/src/Angor/Avalonia/AngorApp/Sections/Wallet/WalletDesign.cs new file mode 100644 index 00000000..63747ac9 --- /dev/null +++ b/src/Angor/Avalonia/AngorApp/Sections/Wallet/WalletDesign.cs @@ -0,0 +1,28 @@ +using System.Threading.Tasks; + +namespace AngorApp.Sections.Wallet; + +public class WalletDesign : IWallet +{ + public IEnumerable History { get; } = + [ + new TransactionDesign { Address = "someaddress1", Amount = 0.0001m, UtxoCount = 12, Path = "path", ViewRawJson = "json" }, + new TransactionDesign { Address = "someaddress2", Amount = 0.0003m, UtxoCount = 15, Path = "path", ViewRawJson = "json" }, + new TransactionDesign { Address = "someaddress3", Amount = 0.0042m, UtxoCount = 15, Path = "path", ViewRawJson = "json" }, + new TransactionDesign { Address = "someaddress4", Amount = 0.00581m, UtxoCount = 15, Path = "path", ViewRawJson = "json" } + ]; + + public decimal? Balance { get; set; } = 2m; + + public async Task CreateTransaction(decimal amount, string address) + { + await Task.Delay(3000); + + //return Result.Failure("Transaction creation failed"); + return new TransactionDesign + { + Address = address, + Amount = amount + }; + } +} \ No newline at end of file diff --git a/src/Angor/Avalonia/AngorApp/Sections/Wallet/WalletView.axaml b/src/Angor/Avalonia/AngorApp/Sections/Wallet/WalletView.axaml index e54cd61c..f8fa8042 100644 --- a/src/Angor/Avalonia/AngorApp/Sections/Wallet/WalletView.axaml +++ b/src/Angor/Avalonia/AngorApp/Sections/Wallet/WalletView.axaml @@ -12,7 +12,7 @@ - + @@ -23,15 +23,7 @@ - - + @@ -61,7 +53,7 @@ - + @@ -71,7 +63,7 @@ @@ -79,7 +71,7 @@ diff --git a/src/Angor/Avalonia/AngorApp/Sections/Wallet/WalletViewModel.cs b/src/Angor/Avalonia/AngorApp/Sections/Wallet/WalletViewModel.cs index a2a10dc0..c8743f7f 100644 --- a/src/Angor/Avalonia/AngorApp/Sections/Wallet/WalletViewModel.cs +++ b/src/Angor/Avalonia/AngorApp/Sections/Wallet/WalletViewModel.cs @@ -1,4 +1,5 @@ -using System.Collections.ObjectModel; +using System.Threading.Tasks; +using CSharpFunctionalExtensions; namespace AngorApp.Sections.Wallet; @@ -17,17 +18,6 @@ public class WalletViewModelDesign : IWalletViewModel public IWallet Wallet { get; set; } = new WalletDesign(); } -public class WalletDesign : IWallet -{ - public IEnumerable History { get; } = - [ - new TransactionDesign() { Address = "someaddress1", Amount = 0.0001m, UtxoCount = 12, Path = "path", ViewRawJson = "json"}, - new TransactionDesign() { Address = "someaddress2", Amount = 0.0003m, UtxoCount = 15, Path = "path", ViewRawJson = "json"}, - new TransactionDesign() { Address = "someaddress3", Amount = 0.0042m, UtxoCount = 15, Path = "path", ViewRawJson = "json"}, - new TransactionDesign() { Address = "someaddress4", Amount = 0.00581m, UtxoCount = 15, Path = "path", ViewRawJson = "json"}, - ]; -} - public class TransactionDesign : ITransaction { public string Address { get; set; } @@ -35,16 +25,20 @@ public class TransactionDesign : ITransaction public string Path { get; set; } public int UtxoCount { get; set; } public string ViewRawJson { get; set; } -} -public interface IWallet -{ - public IEnumerable History { get; } + public async Task Broadcast() + { + await Task.Delay(4000); + //return Result.Failure("Catastrophe!"); + return Result.Success(); + } } -public class WalletModel : IWallet +public interface IWallet { public IEnumerable History { get; } + decimal? Balance { get; set; } + Task CreateTransaction(decimal amount, string address); } public interface ITransaction @@ -54,4 +48,5 @@ public interface ITransaction public string Path { get; } public int UtxoCount { get; } public string ViewRawJson { get; } + Task Broadcast(); } \ No newline at end of file diff --git a/src/Angor/Avalonia/AngorApp/Services/ILauncherService.cs b/src/Angor/Avalonia/AngorApp/Services/ILauncherService.cs deleted file mode 100644 index 2803287b..00000000 --- a/src/Angor/Avalonia/AngorApp/Services/ILauncherService.cs +++ /dev/null @@ -1,8 +0,0 @@ -using System.Threading.Tasks; - -namespace AngorApp.Services; - -public interface ILauncherService -{ - Task Launch(Uri uri); -} \ No newline at end of file diff --git a/src/Angor/Avalonia/AngorApp/Services/LauncherService.cs b/src/Angor/Avalonia/AngorApp/Services/LauncherService.cs deleted file mode 100644 index 20fb3695..00000000 --- a/src/Angor/Avalonia/AngorApp/Services/LauncherService.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System.Threading.Tasks; -using Avalonia.Platform.Storage; - -namespace AngorApp.Services; - -public class LauncherService : ILauncherService -{ - private readonly ILauncher launcher; - - public LauncherService(ILauncher launcher) - { - this.launcher = launcher; - } - - public Task Launch(Uri uri) => launcher.LaunchUriAsync(uri); -} \ No newline at end of file diff --git a/src/Angor/Avalonia/AngorApp/Services/NoopLauncherService.cs b/src/Angor/Avalonia/AngorApp/Services/NoopLauncherService.cs index 60d35031..bf01364c 100644 --- a/src/Angor/Avalonia/AngorApp/Services/NoopLauncherService.cs +++ b/src/Angor/Avalonia/AngorApp/Services/NoopLauncherService.cs @@ -1,10 +1,11 @@ using System.Threading.Tasks; +using Zafiro.Avalonia.Services; namespace AngorApp.Services; public class NoopLauncherService : ILauncherService { - public Task Launch(Uri uri) + public Task LaunchUri(Uri uri) { return Task.CompletedTask; } diff --git a/src/Angor/Avalonia/AngorApp/Services/UIServices.cs b/src/Angor/Avalonia/AngorApp/Services/UIServices.cs index 5169dd99..35de98f0 100644 --- a/src/Angor/Avalonia/AngorApp/Services/UIServices.cs +++ b/src/Angor/Avalonia/AngorApp/Services/UIServices.cs @@ -1,11 +1,19 @@ +using Zafiro.Avalonia.Dialogs; +using Zafiro.Avalonia.Services; +using Zafiro.UI; + namespace AngorApp.Services; public class UIServices { public ILauncherService LauncherService { get; } + public IDialog Dialog { get; } + public INotificationService NotificationService { get; } - public UIServices(ILauncherService launcherService) + public UIServices(ILauncherService launcherService, IDialog dialog, INotificationService notificationService) { LauncherService = launcherService; + Dialog = dialog; + NotificationService = notificationService; } } \ No newline at end of file diff --git a/src/Angor/Avalonia/AngorApp/Styles.axaml b/src/Angor/Avalonia/AngorApp/Styles.axaml index 27b1e4fb..d17002a5 100644 --- a/src/Angor/Avalonia/AngorApp/Styles.axaml +++ b/src/Angor/Avalonia/AngorApp/Styles.axaml @@ -24,7 +24,7 @@ - + @@ -40,17 +40,42 @@ - + + + + + + + + + + + + + + + + + - - - - + + + + + + + diff --git a/src/Angor/Avalonia/Directory.Packages.props b/src/Angor/Avalonia/Directory.Packages.props index 76b0c6a5..3963e884 100644 --- a/src/Angor/Avalonia/Directory.Packages.props +++ b/src/Angor/Avalonia/Directory.Packages.props @@ -20,11 +20,13 @@ + - + + \ No newline at end of file