11using System ;
22using System . Collections . ObjectModel ;
3+ using System . ComponentModel ;
34using System . Linq ;
5+ using System . Runtime . CompilerServices ;
46using System . Threading ;
57using System . Threading . Tasks ;
68using Avalonia ;
79using Avalonia . Controls . ApplicationLifetimes ;
8- using CommunityToolkit . Mvvm . ComponentModel ;
9- using CommunityToolkit . Mvvm . Input ;
1010using FluentAvalonia . UI . Data ;
1111using SharpFM . Core ;
1212
1313namespace SharpFM . App . ViewModels ;
1414
15- public partial class MainWindowViewModel : ViewModelBase
15+ public partial class MainWindowViewModel : INotifyPropertyChanged
1616{
17+ public event PropertyChangedEventHandler ? PropertyChanged ;
18+
19+ private void NotifyPropertyChanged ( [ CallerMemberName ] string propertyName = "" )
20+ {
21+ PropertyChanged ? . Invoke ( this , new PropertyChangedEventArgs ( propertyName ) ) ;
22+ }
23+
1724 public MainWindowViewModel ( )
1825 {
1926 Keys = new ObservableCollection < FileMakerClip > ( ) ;
2027 }
2128
22- [ ObservableProperty ] private string ? _text ;
23-
24- [ RelayCommand ]
25- private void ExitApplication ( )
29+ public void ExitApplication ( )
2630 {
2731 if ( Application . Current ? . ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktopApp )
2832 {
2933 desktopApp . Shutdown ( ) ;
3034 }
3135 }
3236
33- [ RelayCommand ]
34- private void NewEmptyItem ( )
37+ public void NewEmptyItem ( )
3538 {
36- ErrorMessages ? . Clear ( ) ;
3739 try
3840 {
39- Keys . Add ( new FileMakerClip ( "New" , "" , Array . Empty < byte > ( ) ) ) ;
41+ Keys . Add ( new FileMakerClip ( "New" , FileMakerClip . ClipTypes . First ( ) ? . KeyId ?? "" , Array . Empty < byte > ( ) ) ) ;
4042 }
4143 catch ( Exception e )
4244 {
43- ErrorMessages ? . Add ( e . Message ) ;
4445 }
4546 }
4647
47- [ RelayCommand ]
48- private void CopyAsClass ( )
48+ public void CopyAsClass ( )
4949 {
50- ErrorMessages ? . Clear ( ) ;
50+ // TODO: improve the UX of this whole thing. This works as a hack
51+ // for proving the concept, but it could be so much better.
5152 try
5253 {
5354 if ( SelectedClip == null )
@@ -56,7 +57,6 @@ private void CopyAsClass()
5657 return ;
5758 }
5859
59- // TODO: improve the UX of this whole thing. This works as a hack for proving the concept, but it could be so much better.
6060 // See DepInject project for a sample of how to accomplish this.
6161 if ( Application . Current ? . ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime desktop ||
6262 desktop . MainWindow ? . Clipboard is not { } provider )
@@ -67,28 +67,53 @@ private void CopyAsClass()
6767 }
6868 catch ( Exception e )
6969 {
70- ErrorMessages ? . Add ( e . Message ) ;
7170 }
7271 }
7372
74- [ RelayCommand ]
75- private async Task PasteText ( CancellationToken token )
73+ public async Task PasteFileMakerClipData ( CancellationToken token )
7674 {
77- ErrorMessages ? . Clear ( ) ;
7875 try
7976 {
80- await DoGetClipboardDataAsync ( ) ;
77+ // See DepInject project for a sample of how to accomplish this.
78+ if ( Application . Current ? . ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime desktop ||
79+ desktop . MainWindow ? . Clipboard is not { } provider )
80+ throw new NullReferenceException ( "Missing Clipboard instance." ) ;
81+
82+ var formats = await provider . GetFormatsAsync ( ) ;
83+
84+ foreach ( var format in formats . Where ( f => f . StartsWith ( "Mac-" , StringComparison . CurrentCultureIgnoreCase ) ) . Distinct ( ) )
85+ {
86+ if ( string . IsNullOrEmpty ( format ) ) { continue ; }
87+
88+ object ? clipData = await provider . GetDataAsync ( format ) ;
89+
90+ if ( clipData is not byte [ ] dataObj )
91+ {
92+ // this is some type of clipboard data this program can't handle
93+ continue ;
94+ }
95+
96+ var clip = new FileMakerClip ( "new-clip" , format , dataObj ) ;
97+
98+ if ( clip is null ) { continue ; }
99+
100+ // don't bother adding a duplicate. For some reason entries were getting entered twice per clip
101+ // this is not the most efficient method to detect it, but it works well enough for now
102+ if ( Keys . Any ( k => k . XmlData == clip . XmlData ) )
103+ {
104+ continue ;
105+ }
106+
107+ Keys . Add ( clip ) ;
108+ }
81109 }
82110 catch ( Exception e )
83111 {
84- ErrorMessages ? . Add ( e . Message ) ;
85112 }
86113 }
87114
88- [ RelayCommand ]
89- private async Task CopySelectedToClip ( CancellationToken token )
115+ public async Task CopySelectedToClip ( CancellationToken token )
90116 {
91- ErrorMessages ? . Clear ( ) ;
92117 try
93118 {
94119 // See DepInject project for a sample of how to accomplish this.
@@ -98,77 +123,30 @@ private async Task CopySelectedToClip(CancellationToken token)
98123
99124 var dp = new DataPackage ( ) ;
100125
101- if ( ! ( SelectedClip is FileMakerClip data ) )
126+ if ( SelectedClip is not FileMakerClip data )
102127 {
103128 return ; // no data
104129 }
105130
106- // recalculate the length of the original text and make sure that is the first four bytes in the stream
107- //var code = data.RawData;// XamlCodeRenderer.Text;
108- //byte[] byteList = Encoding.UTF8.GetBytes(code);
109- //int bl = byteList.Length;
110- //byte[] intBytes = BitConverter.GetBytes(bl);
111-
112- //dp.SetData("Mac-XMSS", intBytes.Concat(byteList).ToArray().AsBuffer().AsStream().AsRandomAccessStream());
113131 dp . SetData ( data . ClipboardFormat , data . RawData ) ;
114132
115133 await provider . SetDataObjectAsync ( dp ) ;
116134 }
117135 catch ( Exception e )
118136 {
119- ErrorMessages ? . Add ( e . Message ) ;
120137 }
121138 }
122- private async Task DoGetClipboardDataAsync ( )
123- {
124- // For learning purposes, we opted to directly get the reference
125- // for StorageProvider APIs here inside the ViewModel.
126-
127- // For your real-world apps, you should follow the MVVM principles
128- // by making service classes and locating them with DI/IoC.
129-
130- // See DepInject project for a sample of how to accomplish this.
131- if ( Application . Current ? . ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime desktop ||
132- desktop . MainWindow ? . Clipboard is not { } provider )
133- throw new NullReferenceException ( "Missing Clipboard instance." ) ;
134139
135- var formats = await provider . GetFormatsAsync ( ) ;
140+ public ObservableCollection < FileMakerClip > Keys { get ; set ; }
136141
137- foreach ( var format in formats . Where ( f => f . StartsWith ( "Mac-" , StringComparison . CurrentCultureIgnoreCase ) ) . Distinct ( ) )
142+ private FileMakerClip ? _selectedClip ;
143+ public FileMakerClip ? SelectedClip
144+ {
145+ get => _selectedClip ;
146+ set
138147 {
139- if ( string . IsNullOrEmpty ( format ) ) { continue ; }
140-
141- object ? clipData = await provider . GetDataAsync ( format ) ;
142-
143- if ( ! ( clipData is byte [ ] dataObj ) )
144- {
145- // this is some type of clipboard data this program can't handle
146- continue ;
147- }
148-
149- var clip = new FileMakerClip ( "new-clip" , format , dataObj ) ;
150-
151- if ( clip is null ) { continue ; }
152-
153- // don't bother adding a duplicate. For some reason entries were getting entered twice per clip
154- // this is not the most efficient method to detect it, but it works well enough for now
155- if ( Keys . Any ( k => k . XmlData == clip . XmlData ) )
156- {
157- continue ;
158- }
159-
160- Keys . Add ( clip ) ;
148+ _selectedClip = value ;
149+ NotifyPropertyChanged ( ) ;
161150 }
162151 }
163-
164- [ ObservableProperty ]
165- private ObservableCollection < FileMakerClip > _keys ;
166-
167- //public ObservableCollection<FileMakerClip> Layouts { get; }
168-
169- [ ObservableProperty ]
170- private FileMakerClip ? _selectedLayout ;
171-
172- [ ObservableProperty ]
173- private FileMakerClip ? _selectedClip ;
174152}
0 commit comments