22using AndroidX . Core . Content ;
33using CommunityToolkit . Maui . Storage ;
44using Grpc . Net . Client . Web ;
5+ using HavenoSharp . Models ;
56using HavenoSharp . Services ;
67using HavenoSharp . Singletons ;
78using Manta . Helpers ;
@@ -72,13 +73,33 @@ public partial class Settings : ComponentBase, IDisposable
7273
7374 public bool ShowRestoreModal { get ; set ; }
7475
75- public bool ShowConnectToMoneroNodeModal { get ; set ; }
76+ public bool ShowAddMoneroNodeModal { get ; set ; }
7677
7778 Timer ? ValidateMoneroNodeUrlTimer { get ; set ; }
7879
7980 public string ? IsMoneroNodeUrlInvalidReason { get ; set ; }
8081 public bool IsMoneroNodeUrlInvalid { get ; set ; }
8182
83+ public bool ShowRemoveMoneroNodeModal { get ; set ; }
84+ public string ? MoneroNodeToRemove { get ; set ; }
85+ public bool ShowConnectToMoneroNodeModal { get ; set ; }
86+ public string ? MoneroNodeToConnectTo { get ; set ; }
87+
88+ public bool IsAutoSwitchEnabled { get ; set ; }
89+
90+ public bool AuthenticationRequired
91+ {
92+ get ;
93+ set
94+ {
95+ field = value ;
96+ MoneroNodeUsername = null ;
97+ MoneroNodePassword = null ;
98+ }
99+ }
100+
101+ public List < UrlConnection > UrlConnections { get ; set ; } = [ ] ;
102+
82103 public string ? MoneroNodePassword { get ; set { field = value ? . Trim ( ) ; } }
83104 public string ? MoneroNodeUrl
84105 {
@@ -103,6 +124,9 @@ public async Task ValidateUrl(string field)
103124 {
104125 try
105126 {
127+ if ( field is null )
128+ return ;
129+
106130 if ( field == string . Empty )
107131 {
108132 IsMoneroNodeUrlInvalidReason = null ;
@@ -401,23 +425,95 @@ public async Task ScanQRCodeAsync()
401425 await current . MainPage . Navigation . PopModalAsync ( true ) ;
402426 }
403427
404- public async Task ConnectToMoneroNodeAsync ( )
428+ public async Task SetAutoSwitchAsync ( bool value )
405429 {
406- // Should show error etc
407- if ( MoneroNodeUrl is null )
408- return ;
430+ await HavenoXmrNodeService . SetAutoSwitchAsync ( value ) ;
431+ }
432+
433+ public async Task AddMoneroNodeAsync ( )
434+ {
435+ if ( string . IsNullOrEmpty ( MoneroNodeUrl ) )
436+ throw new Exception ( "Url cannot be empty." ) ;
437+
438+ MoneroNodeUsername ??= string . Empty ;
439+ MoneroNodePassword ??= string . Empty ;
440+
441+ await HavenoXmrNodeService . AddConnectionAsync ( MoneroNodeUrl , MoneroNodeUsername , MoneroNodePassword , 0 ) ;
442+
443+ // Not ideal but Haveno requires the username/password again when setting the node even if it is saved
444+ var savedNodes = AppPreferences . Get < List < MoneroNodeInfo > > ( AppPreferences . SavedXmrNodes ) ?? [ ] ;
445+ MoneroNodeInfo ? moneroNodeInfo = savedNodes . FirstOrDefault ( x => x . Url == MoneroNodeUrl ) ;
446+ if ( moneroNodeInfo is null )
447+ {
448+ moneroNodeInfo = new MoneroNodeInfo
449+ {
450+ Url = MoneroNodeUrl ,
451+ Password = MoneroNodePassword ,
452+ Username = MoneroNodeUsername
453+ } ;
454+
455+ savedNodes . Add ( moneroNodeInfo ) ;
456+ }
457+ else
458+ {
459+ // This shouldn't happen?
460+
461+ moneroNodeInfo . Password = MoneroNodePassword ;
462+ moneroNodeInfo . Username = MoneroNodeUsername ;
463+ }
464+
465+ AppPreferences . Set ( AppPreferences . SavedXmrNodes , savedNodes ) ;
466+
467+ UrlConnections = await HavenoXmrNodeService . GetConnectionsAsync ( ) ;
468+
469+ MoneroNodeUrl = null ;
470+ MoneroNodeUsername = null ;
471+ MoneroNodePassword = null ;
472+
473+ AuthenticationRequired = false ;
474+ }
475+
476+ public async Task RemoveMoneroNodeAsync ( string url )
477+ {
478+ var connectedNode = await HavenoXmrNodeService . GetMoneroNodeAsync ( ) ;
479+ if ( connectedNode . Url == url )
480+ throw new Exception ( "Cannot remove the selected node as it is currently in use." ) ;
481+
482+ await HavenoXmrNodeService . RemoveConnectionAsync ( url ) ;
483+
484+ var savedNodes = AppPreferences . Get < List < MoneroNodeInfo > > ( AppPreferences . SavedXmrNodes ) ?? [ ] ;
485+ MoneroNodeInfo ? moneroNodeInfo = savedNodes . FirstOrDefault ( x => x . Url == url ) ;
486+ if ( moneroNodeInfo is not null )
487+ {
488+ savedNodes . Remove ( moneroNodeInfo ) ;
489+ AppPreferences . Set ( AppPreferences . SavedXmrNodes , savedNodes ) ;
490+ }
491+
492+ UrlConnections = await HavenoXmrNodeService . GetConnectionsAsync ( ) ;
493+ }
409494
495+ public async Task ConnectToMoneroNodeAsync ( string url )
496+ {
410497 MoneroNodeConnectCancellationTokenSource = new ( 10_000 ) ;
411498 IsConnectingToMoneroNode = true ;
412499
413500 try
414501 {
415- MoneroNodeUsername ??= string . Empty ;
416- MoneroNodePassword ??= string . Empty ;
502+ var moneroNodeUsername = string . Empty ;
503+ var moneroNodePassword = string . Empty ;
504+
505+ var savedNodes = AppPreferences . Get < List < MoneroNodeInfo > > ( AppPreferences . SavedXmrNodes ) ?? [ ] ;
506+ MoneroNodeInfo ? moneroNodeInfo = savedNodes . FirstOrDefault ( x => x . Url == url ) ;
507+ if ( moneroNodeInfo is not null )
508+ {
509+ moneroNodeUsername = moneroNodeInfo . Username ;
510+ moneroNodePassword = moneroNodeInfo . Password ;
511+ }
417512
418513 // Does not throw an exception if fails?
514+ IsAutoSwitchEnabled = false ;
419515 await HavenoXmrNodeService . SetAutoSwitchAsync ( false ) ;
420- await HavenoXmrNodeService . SetMoneroNodeAsync ( MoneroNodeUrl , MoneroNodeUsername , MoneroNodePassword , 0 ) ;
516+ await HavenoXmrNodeService . SetMoneroNodeAsync ( url , moneroNodeUsername , moneroNodePassword , 0 ) ;
421517
422518 var response = await HavenoXmrNodeService . GetMoneroNodeAsync ( ) ;
423519 ConnectedMoneroNodeUrl = response . Url ;
@@ -433,7 +529,7 @@ public async Task ConnectToMoneroNodeAsync()
433529 break ;
434530 }
435531
436- if ( response . OnlineStatus == HavenoSharp . Models . OnlineStatus . ONLINE )
532+ if ( response . OnlineStatus == OnlineStatus . ONLINE )
437533 break ;
438534
439535 await Task . Delay ( 500 ) ;
@@ -442,34 +538,29 @@ public async Task ConnectToMoneroNodeAsync()
442538 if ( MoneroNodeConnectCancellationTokenSource . IsCancellationRequested )
443539 {
444540 await HavenoXmrNodeService . SetAutoSwitchAsync ( true ) ;
445- await HavenoXmrNodeService . RemoveConnectionAsync ( MoneroNodeUrl ) ;
446-
447- var moneroNodes = await HavenoXmrNodeService . GetConnectionsAsync ( ) ;
448- var previousAuthedNode = moneroNodes . FirstOrDefault ( x => x . AuthenticationStatus == HavenoSharp . Models . AuthenticationStatus . AUTHENTICATED && x . OnlineStatus == HavenoSharp . Models . OnlineStatus . ONLINE ) ;
541+ IsAutoSwitchEnabled = true ;
449542
450- if ( previousAuthedNode is not null ) // Hope that previous node did not require auth
451- await HavenoXmrNodeService . SetMoneroNodeAsync ( previousAuthedNode . Url , string . Empty , string . Empty , 0 ) ;
543+ var moneroNode = await HavenoXmrNodeService . GetBestConnectionAsync ( ) ;
544+ await HavenoXmrNodeService . SetMoneroNodeAsync ( moneroNode . Url , string . Empty , string . Empty , 0 ) ;
452545
453546 response = await HavenoXmrNodeService . GetMoneroNodeAsync ( ) ;
454547 ConnectedMoneroNodeUrl = response . Url ;
455548
456- throw new Exception ( "Failed to connect to node." ) ;
457- }
458- else
459- {
460- AppPreferences . Set ( AppPreferences . CustomXmrNode , ConnectedMoneroNodeUrl ) ;
549+ throw new Exception ( "Failed to connect to node. Please check that the node is online and that the login details are correct." ) ;
461550 }
462551 }
463552 finally
464553 {
465- ShowConnectToMoneroNodeModal = false ;
554+ ShowAddMoneroNodeModal = false ;
466555 MoneroNodeUrl = string . Empty ;
467556 MoneroNodeUsername = string . Empty ;
468557 MoneroNodePassword = string . Empty ;
469558
470559 MoneroNodeConnectCancellationTokenSource . Dispose ( ) ;
471560 MoneroNodeConnectCancellationTokenSource = null ;
472561 IsConnectingToMoneroNode = false ;
562+
563+ UrlConnections = await HavenoXmrNodeService . GetConnectionsAsync ( ) ;
473564 }
474565 }
475566
@@ -528,29 +619,7 @@ public async Task ConnectToRemoteNodeAsync()
528619 ConnectionError = "Could not connect to remote node. Make sure Orbot is installed and configured." ;
529620 }
530621
531- public async Task HandleRemoteNodeToggleAsync ( bool isToggled )
532- {
533- // Prompt that account won't be synced and that if running, local daemon, termux etc needs to be stopped
534- if ( ! isToggled )
535- {
536- // Theres a small issue if orbot is running at the same time as it listens to the same ports that the Termux tor instance listens on, however users should not be regularly switching hosting modes
537- await SecureStorageHelper . SetAsync ( "daemon-installation-type" , DaemonInstallOptions . Standalone ) ;
538-
539- if ( ( await HavenoDaemonService . GetIsDaemonInstalledAsync ( ) ) . Item1 )
540- {
541- await HavenoDaemonService . TryStartLocalHavenoDaemonAsync ( Guid . NewGuid ( ) . ToString ( ) , "http://127.0.0.1:3201" ) ;
542- }
543- else
544- {
545- NavigationManager . NavigateTo ( "/" ) ;
546- }
547-
548- Password = null ;
549- Host = null ;
550- }
551- }
552-
553- public async Task HandleToggleAsync ( bool isToggled )
622+ public async Task HandleNotificationsToggleAsync ( bool isToggled )
554623 {
555624#if ANDROID
556625 if ( isToggled )
@@ -581,16 +650,6 @@ public async Task HandleWakeLockToggle(bool isToggled)
581650#endif
582651 }
583652
584- protected override async Task OnAfterRenderAsync ( bool firstRender )
585- {
586- if ( firstRender )
587- {
588-
589- }
590-
591- await base . OnAfterRenderAsync ( firstRender ) ;
592- }
593-
594653 private async void HandleDaemonInfoFetch ( bool isFetching )
595654 {
596655 await InvokeAsync ( ( ) => {
@@ -637,6 +696,9 @@ protected override async Task OnInitializedAsync()
637696 IsXmrNodeOnline = DaemonInfoSingleton . IsXmrNodeOnline ;
638697 ConnectedMoneroNodeUrl = DaemonInfoSingleton . ConnectedMoneroNodeUrl ;
639698
699+ IsAutoSwitchEnabled = await HavenoXmrNodeService . GetAutoSwitchAsync ( ) ;
700+ UrlConnections = await HavenoXmrNodeService . GetConnectionsAsync ( ) ;
701+
640702 DaemonInfoSingleton . OnDaemonInfoFetch += HandleDaemonInfoFetch ;
641703 DaemonConnectionSingleton . OnConnectionChanged += HandleDaemonConnectionChanged ;
642704
0 commit comments