55
66using Avalonia . Input . Platform ;
77using System ;
8- using System . Collections . Generic ;
98using System . Collections . ObjectModel ;
10- using System . ComponentModel ;
9+ using System . Diagnostics ;
1110using System . Linq ;
1211using System . Reflection ;
12+ using System . Threading . Tasks ;
1313using WatchOnlyBitcoinWallet . Models ;
1414using WatchOnlyBitcoinWallet . MVVM ;
1515using WatchOnlyBitcoinWallet . Services ;
@@ -24,9 +24,7 @@ public MainWindowViewModel()
2424 WindowMan = new WindowManager ( ) ;
2525 FileMan = new FileManager ( ) ;
2626
27- AddressList = new BindingList < BitcoinAddress > ( FileMan . ReadWalletFile ( ) ) ;
28- AddressList . ListChanged += AddressList_ListChanged ;
29-
27+ AddressList = new ( FileMan . ReadWalletFile ( ) ) ;
3028 SettingsInstance = FileMan . ReadSettingsFile ( ) ;
3129
3230 GetBalanceCommand = new BindableCommand ( GetBalance , ( ) => ! IsReceiving ) ;
@@ -37,37 +35,53 @@ public MainWindowViewModel()
3735 ImportFromTextCommand = new BindableCommand ( ImportFromText ) ;
3836 ImportFromFileCommand = new BindableCommand ( ImportFromFile ) ;
3937
38+ AddCommand = new ( Add ) ;
39+ RemoveCommand = new ( Remove , ( ) => SelectedAddress is not null ) ;
40+ EditCommand = new ( Edit , ( ) => SelectedAddress is not null ) ;
41+ MoveUpCommand = new ( MoveUp , ( ) => SelectedIndex > 0 ) ;
42+ MoveDownCommand = new ( MoveDown , ( ) => SelectedIndex >= 0 && SelectedIndex < AddressList . Count - 1 ) ;
43+
4044 Version ver = Assembly . GetExecutingAssembly ( ) . GetName ( ) . Version ?? new Version ( ) ;
4145 VersionString = string . Format ( "Version {0}.{1}.{2}" , ver . Major , ver . Minor , ver . Build ) ;
4246 }
4347
4448
4549
46- void AddressList_ListChanged ( object sender , ListChangedEventArgs e )
50+ public ObservableCollection < BitcoinAddress > AddressList { get ; set ; }
51+
52+ private BitcoinAddress ? _selAddr ;
53+ public BitcoinAddress ? SelectedAddress
4754 {
48- if ( e . ListChangedType == ListChangedType . ItemChanged )
55+ get => _selAddr ;
56+ set
4957 {
50- BitcoinAddress addr = ( ( BindingList < BitcoinAddress > ) sender ) [ e . NewIndex ] ;
51- if ( addr . Address != null )
52- {
53- addr . Validate ( addr . Address ) ;
54- }
55- if ( ! addr . HasErrors )
58+ if ( SetField ( ref _selAddr , value ) )
5659 {
57- DataManager . WriteFile ( AddressList , DataManager . FileType . Wallet ) ;
60+ RemoveCommand . RaiseCanExecuteChanged ( ) ;
61+ EditCommand . RaiseCanExecuteChanged ( ) ;
5862 }
5963 }
60- else if ( e . ListChangedType == ListChangedType . ItemDeleted || e . ListChangedType == ListChangedType . ItemAdded )
64+ }
65+
66+ private int _selIndex = - 1 ;
67+ public int SelectedIndex
68+ {
69+ get => _selIndex ;
70+ set
6171 {
62- DataManager . WriteFile ( AddressList , DataManager . FileType . Wallet ) ;
72+ if ( SetField ( ref _selIndex , value ) )
73+ {
74+ MoveUpCommand . RaiseCanExecuteChanged ( ) ;
75+ MoveDownCommand . RaiseCanExecuteChanged ( ) ;
76+ }
6377 }
6478 }
6579
66-
67- public IWindowManager WindowMan { get ; set ; }
6880 public IClipboard Clipboard { get ; set ; }
6981 public IFileManager FileMan { get ; set ; }
70-
82+ public IWindowManager WindowMan { get ; set ; }
83+ public SettingsModel SettingsInstance { get ; }
84+ public string VersionString { get ; }
7185
7286 /// <summary>
7387 /// Indicating an active connection.
@@ -86,18 +100,6 @@ public bool IsReceiving
86100 }
87101 private bool isReceiving ;
88102
89- public string VersionString { get ; private set ; }
90-
91-
92- public BindingList < BitcoinAddress > AddressList { get ; set ; }
93-
94-
95- private SettingsModel settingsInstance ;
96- public SettingsModel SettingsInstance
97- {
98- get { return settingsInstance ; }
99- set { SetField ( ref settingsInstance , value ) ; }
100- }
101103
102104 public decimal BitcoinBalance
103105 {
@@ -126,6 +128,36 @@ public decimal BitcoinBalanceLC
126128 }
127129
128130
131+ private void SaveWallet ( )
132+ {
133+ FileMan . WriteWallet ( AddressList . ToList ( ) ) ;
134+ }
135+
136+ private readonly object lockObj = new ( ) ;
137+ private bool isSavePending = false ;
138+ private async void QueueSaveWallet ( )
139+ {
140+ lock ( lockObj )
141+ {
142+ if ( isSavePending )
143+ {
144+ return ;
145+ }
146+ else
147+ {
148+ isSavePending = true ;
149+ }
150+ }
151+
152+ await Task . Delay ( TimeSpan . FromSeconds ( 10 ) ) ;
153+ lock ( lockObj )
154+ {
155+ SaveWallet ( ) ;
156+ isSavePending = false ;
157+ }
158+ }
159+
160+
129161 public BindableCommand OpenAboutCommand { get ; private set ; }
130162 private async void OpenAbout ( )
131163 {
@@ -255,5 +287,92 @@ private async void GetBalance()
255287 IsReceiving = false ;
256288 }
257289
290+
291+ public BindableCommand AddCommand { get ; }
292+ public async void Add ( )
293+ {
294+ AddEditViewModel vm = new ( ) ;
295+ await WindowMan . ShowDialog ( vm ) ;
296+ if ( vm . IsChanged )
297+ {
298+ BitcoinAddress t = new ( )
299+ {
300+ Address = vm . AddressString ,
301+ Name = vm . Tag
302+ } ;
303+ AddressList . Add ( t ) ;
304+ SaveWallet ( ) ;
305+ }
306+ }
307+
308+ public BindableCommand RemoveCommand { get ; }
309+ private void Remove ( )
310+ {
311+ if ( SelectedAddress is not null )
312+ {
313+ AddressList . Remove ( SelectedAddress ) ;
314+ SaveWallet ( ) ;
315+ }
316+ else
317+ {
318+ Errors = "Nothing is selected!" ;
319+ }
320+ }
321+
322+ public BindableCommand EditCommand { get ; }
323+ public async void Edit ( )
324+ {
325+ if ( SelectedAddress is not null )
326+ {
327+ AddEditViewModel vm = new ( )
328+ {
329+ AddressString = SelectedAddress . Address ,
330+ Tag = SelectedAddress . Name
331+ } ;
332+
333+ await WindowMan . ShowDialog ( vm ) ;
334+ if ( vm . IsChanged )
335+ {
336+ SelectedAddress . Address = vm . AddressString ;
337+ SelectedAddress . Name = vm . Tag ;
338+
339+ SaveWallet ( ) ;
340+ }
341+ }
342+ else
343+ {
344+ Errors = "Nothing is selected!" ;
345+ }
346+ }
347+
348+ public BindableCommand MoveUpCommand { get ; }
349+ private void MoveUp ( )
350+ {
351+ Debug . Assert ( SelectedIndex != - 1 ) ; // selected is not null
352+ Debug . Assert ( SelectedIndex != 0 ) ; // selected is not first item
353+
354+ // When items are swapped, the selected item turns into null so SelectedIndex value will turn into -1.
355+ // Store it here to use later when setting the new selected item
356+ int i = SelectedIndex ;
357+ ( AddressList [ i - 1 ] , AddressList [ i ] ) = ( AddressList [ i ] , AddressList [ i - 1 ] ) ;
358+ SelectedAddress = AddressList [ i - 1 ] ;
359+
360+ QueueSaveWallet ( ) ;
361+ }
362+
363+ public BindableCommand MoveDownCommand { get ; }
364+ private void MoveDown ( )
365+ {
366+ Debug . Assert ( SelectedIndex != - 1 ) ; // selected is not null
367+ Debug . Assert ( SelectedIndex != AddressList . Count - 1 ) ; // selected is not last item
368+
369+ // When items are swapped, the selected item turns into null so SelectedIndex value will turn into -1.
370+ // Store it here to use later when setting the new selected item
371+ int i = SelectedIndex ;
372+ ( AddressList [ i + 1 ] , AddressList [ i ] ) = ( AddressList [ i ] , AddressList [ i + 1 ] ) ;
373+ SelectedAddress = AddressList [ i + 1 ] ;
374+
375+ QueueSaveWallet ( ) ;
376+ }
258377 }
259378}
0 commit comments