11using ByteSizeLib ;
2- using Files . Interacts ;
2+ using Files . Enums ;
33using Files . Navigation ;
44using Microsoft . Toolkit . Uwp . UI ;
55using Microsoft . UI . Xaml . Controls ;
66using System ;
77using System . Collections . Generic ;
88using System . Collections . ObjectModel ;
9+ using System . ComponentModel ;
910using System . Diagnostics ;
1011using System . Globalization ;
1112using System . IO ;
1213using System . Linq ;
14+ using System . Runtime . CompilerServices ;
1315using System . Runtime . InteropServices ;
1416using System . Threading ;
1517using System . Threading . Tasks ;
3133
3234namespace Files . Filesystem
3335{
34- public class ItemViewModel
36+ public class ItemViewModel : INotifyPropertyChanged
3537 {
3638 public ReadOnlyObservableCollection < ListedItem > FilesAndFolders { get ; }
3739 public CollectionViewSource viewSource ;
@@ -44,10 +46,133 @@ public class ItemViewModel
4446 private QueryOptions _options ;
4547 private volatile bool _filesRefreshing ;
4648 private const int _step = 250 ;
49+ public event PropertyChangedEventHandler PropertyChanged ;
50+
51+ private SortOption _directorySortOption = SortOption . Name ;
52+ private SortDirection _directorySortDirection = SortDirection . Ascending ;
53+
54+ public SortOption DirectorySortOption
55+ {
56+ get
57+ {
58+ return _directorySortOption ;
59+ }
60+ set
61+ {
62+ if ( value != _directorySortOption )
63+ {
64+ _directorySortOption = value ;
65+ NotifyPropertyChanged ( "DirectorySortOption" ) ;
66+ NotifyPropertyChanged ( "IsSortedByName" ) ;
67+ NotifyPropertyChanged ( "IsSortedByDate" ) ;
68+ NotifyPropertyChanged ( "IsSortedByType" ) ;
69+ NotifyPropertyChanged ( "IsSortedBySize" ) ;
70+ OrderFiles ( ) ;
71+ }
72+ }
73+ }
74+
75+ public SortDirection DirectorySortDirection
76+ {
77+ get
78+ {
79+ return _directorySortDirection ;
80+ }
81+ set
82+ {
83+ if ( value != _directorySortDirection )
84+ {
85+ _directorySortDirection = value ;
86+ NotifyPropertyChanged ( "DirectorySortDirection" ) ;
87+ NotifyPropertyChanged ( "IsSortedAscending" ) ;
88+ NotifyPropertyChanged ( "IsSortedDescending" ) ;
89+ OrderFiles ( ) ;
90+ }
91+ }
92+ }
93+
94+ public bool IsSortedByName
95+ {
96+ get => DirectorySortOption == SortOption . Name ;
97+ set
98+ {
99+ if ( value )
100+ {
101+ DirectorySortOption = SortOption . Name ;
102+ NotifyPropertyChanged ( "IsSortedByName" ) ;
103+ NotifyPropertyChanged ( "DirectorySortOption" ) ;
104+ }
105+ }
106+ }
107+
108+ public bool IsSortedByDate
109+ {
110+ get => DirectorySortOption == SortOption . DateModified ;
111+ set
112+ {
113+ if ( value )
114+ {
115+ DirectorySortOption = SortOption . DateModified ;
116+ NotifyPropertyChanged ( "IsSortedByDate" ) ;
117+ NotifyPropertyChanged ( "DirectorySortOption" ) ;
118+ }
119+ }
120+ }
121+
122+ public bool IsSortedByType
123+ {
124+ get => DirectorySortOption == SortOption . FileType ;
125+ set
126+ {
127+ if ( value )
128+ {
129+ DirectorySortOption = SortOption . FileType ;
130+ NotifyPropertyChanged ( "IsSortedByType" ) ;
131+ NotifyPropertyChanged ( "DirectorySortOption" ) ;
132+ }
133+ }
134+ }
135+
136+ public bool IsSortedBySize
137+ {
138+ get => DirectorySortOption == SortOption . Size ;
139+ set
140+ {
141+ if ( value )
142+ {
143+ DirectorySortOption = SortOption . Size ;
144+ NotifyPropertyChanged ( "IsSortedBySize" ) ;
145+ NotifyPropertyChanged ( "DirectorySortOption" ) ;
146+ }
147+ }
148+ }
149+
150+ public bool IsSortedAscending
151+ {
152+ get => DirectorySortDirection == SortDirection . Ascending ;
153+ set
154+ {
155+ DirectorySortDirection = value ? SortDirection . Ascending : SortDirection . Descending ;
156+ NotifyPropertyChanged ( "IsSortedAscending" ) ;
157+ NotifyPropertyChanged ( "IsSortedDescending" ) ;
158+ NotifyPropertyChanged ( "DirectorySortDirection" ) ;
159+ }
160+ }
161+
162+ public bool IsSortedDescending
163+ {
164+ get => ! IsSortedAscending ;
165+ set
166+ {
167+ DirectorySortDirection = value ? SortDirection . Descending : SortDirection . Ascending ;
168+ NotifyPropertyChanged ( "IsSortedAscending" ) ;
169+ NotifyPropertyChanged ( "IsSortedDescending" ) ;
170+ NotifyPropertyChanged ( "DirectorySortDirection" ) ;
171+ }
172+ }
47173
48174 public ItemViewModel ( )
49175 {
50-
51176 _filesAndFolders = new ObservableCollection < ListedItem > ( ) ;
52177
53178 FilesAndFolders = new ReadOnlyObservableCollection < ListedItem > ( _filesAndFolders ) ;
@@ -250,6 +375,59 @@ public void CancelLoadAndClearFiles()
250375
251376 }
252377
378+ public void OrderFiles ( )
379+ {
380+ if ( _filesAndFolders . Count == 0 )
381+ return ;
382+
383+ object orderByNameFunc ( ListedItem item ) => item . FileName ;
384+ Func < ListedItem , object > orderFunc = orderByNameFunc ;
385+ switch ( DirectorySortOption )
386+ {
387+ case SortOption . Name :
388+ orderFunc = orderByNameFunc ;
389+ break ;
390+ case SortOption . DateModified :
391+ orderFunc = item => item . FileDateReal ;
392+ break ;
393+ case SortOption . FileType :
394+ orderFunc = item => item . FileType ;
395+ break ;
396+ case SortOption . Size :
397+ orderFunc = item => item . FileSizeBytes ;
398+ break ;
399+ }
400+
401+ // In ascending order, show folders first, then files.
402+ // So, we use != "Folder" to make the value for "Folder" = 0, and for the rest, 1.
403+ Func < ListedItem , bool > folderThenFile = listedItem => listedItem . FileType != "Folder" ;
404+ IOrderedEnumerable < ListedItem > ordered ;
405+ List < ListedItem > orderedList ;
406+
407+ if ( DirectorySortDirection == SortDirection . Ascending )
408+ ordered = _filesAndFolders . OrderBy ( folderThenFile ) . ThenBy ( orderFunc ) ;
409+ else
410+ {
411+ if ( DirectorySortOption == SortOption . FileType )
412+ ordered = _filesAndFolders . OrderBy ( folderThenFile ) . ThenByDescending ( orderFunc ) ;
413+ else
414+ ordered = _filesAndFolders . OrderByDescending ( folderThenFile ) . ThenByDescending ( orderFunc ) ;
415+ }
416+
417+ // Further order by name if applicable
418+ if ( DirectorySortOption != SortOption . Name )
419+ {
420+ if ( DirectorySortDirection == SortDirection . Ascending )
421+ ordered = ordered . ThenBy ( orderByNameFunc ) ;
422+ else
423+ ordered = ordered . ThenByDescending ( orderByNameFunc ) ;
424+ }
425+ orderedList = ordered . ToList ( ) ;
426+ _filesAndFolders . Clear ( ) ;
427+ foreach ( ListedItem i in orderedList )
428+ _filesAndFolders . Add ( i ) ;
429+ }
430+
253431 public static T GetCurrentSelectedTabInstance < T > ( )
254432 {
255433 Frame rootFrame = Window . Current . Content as Frame ;
@@ -435,6 +613,7 @@ public async void AddItemsToCollectionAsync(string path)
435613 ( App . selectedTabInstance . accessibleContentFrame . Content as PhotoAlbum ) . TextState . isVisible = Visibility . Visible ;
436614 }
437615 }
616+ OrderFiles ( ) ;
438617 stopwatch . Stop ( ) ;
439618 Debug . WriteLine ( "Loading of items in " + Universal . path + " completed in " + stopwatch . ElapsedMilliseconds + " milliseconds.\n " ) ;
440619 App . selectedTabInstance . RefreshButton . IsEnabled = true ;
@@ -517,7 +696,7 @@ private async Task AddFolder(StorageFolder folder)
517696 FilePath = folder . Path ,
518697 EmptyImgVis = Visibility . Collapsed ,
519698 FileSize = null ,
520- RowIndex = _filesAndFolders . Count
699+ FileSizeBytes = 0
521700 } ) ;
522701 if ( ( App . selectedTabInstance . accessibleContentFrame . Content as GenericFileBrowser ) != null )
523702 {
@@ -538,6 +717,7 @@ private async Task AddFile(StorageFile file)
538717 var itemDate = basicProperties . DateModified ;
539718 var itemPath = file . Path ;
540719 var itemSize = ByteSize . FromBytes ( basicProperties . Size ) . ToString ( ) ;
720+ var itemSizeBytes = basicProperties . Size ;
541721 var itemType = file . DisplayType ;
542722 var itemFolderImgVis = Visibility . Collapsed ;
543723 var itemFileExtension = file . FileType ;
@@ -616,7 +796,7 @@ private async Task AddFile(StorageFile file)
616796 FileType = itemType ,
617797 FilePath = itemPath ,
618798 FileSize = itemSize ,
619- RowIndex = _filesAndFolders . Count
799+ FileSizeBytes = itemSizeBytes
620800 } ) ;
621801
622802 if ( App . selectedTabInstance . accessibleContentFrame . SourcePageType == typeof ( GenericFileBrowser ) )
@@ -724,5 +904,9 @@ await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPrio
724904 _filesRefreshing = false ;
725905 Debug . WriteLine ( "Filesystem refresh complete" ) ;
726906 }
907+ private void NotifyPropertyChanged ( [ CallerMemberName ] string propertyName = "" )
908+ {
909+ PropertyChanged ? . Invoke ( this , new PropertyChangedEventArgs ( propertyName ) ) ;
910+ }
727911 }
728912}
0 commit comments