@ -8,7 +8,9 @@ using System.Reactive.Linq;
using System.Threading.Tasks ;
using AsyncAwaitBestPractices ;
using AsyncImageLoader ;
using Avalonia ;
using Avalonia.Controls ;
using Avalonia.Media ;
using Avalonia.Threading ;
using CommunityToolkit.Mvvm.ComponentModel ;
using DynamicData ;
@ -81,6 +83,9 @@ public partial class OutputsPageViewModel : PageViewModelBase
[ObservableProperty]
private Size imageSize = new ( 3 0 0 , 3 0 0 ) ;
[ObservableProperty]
private bool isConsolidating ;
public bool CanShowOutputTypes = >
SelectedCategory ? . Name ? . Equals ( "Shared Output Folder" ) ? ? false ;
@ -115,8 +120,8 @@ public partial class OutputsPageViewModel : PageViewModelBase
. Connect ( )
. DeferUntilLoaded ( )
. Filter ( searchPredicate )
. SortBy ( file = > file . CreatedAt , SortDirection . Descending )
. Transform ( file = > new OutputImageViewModel ( file ) )
. SortBy ( vm = > vm . ImageFile . CreatedAt , SortDirection . Descending )
. Bind ( Outputs )
. WhenPropertyChanged ( p = > p . IsSelected )
. Subscribe ( _ = >
@ -141,6 +146,7 @@ public partial class OutputsPageViewModel : PageViewModelBase
return ;
Directory . CreateDirectory ( settingsManager . ImagesDirectory ) ;
var packageCategories = settingsManager . Settings . InstalledPackages
. Where ( x = > ! x . UseSharedOutputFolder )
. Select ( p = >
@ -166,6 +172,15 @@ public partial class OutputsPageViewModel : PageViewModelBase
}
) ;
packageCategories . Insert (
1 ,
new PackageOutputCategory
{
Path = settingsManager . ImagesInferenceDirectory ,
Name = "Inference"
}
) ;
Categories = new ObservableCollection < PackageOutputCategory > ( packageCategories ) ;
SelectedCategory = Categories . First ( ) ;
SelectedOutputType = SharedOutputType . All ;
@ -206,7 +221,7 @@ public partial class OutputsPageViewModel : PageViewModelBase
GetOutputs ( path ) ;
}
public async Task OnImageClick ( OutputImageViewModel item )
public Task OnImageClick ( OutputImageViewModel item )
{
// Select image if we're in "select mode"
if ( NumItemsSelected > 0 )
@ -215,8 +230,10 @@ public partial class OutputsPageViewModel : PageViewModelBase
}
else
{
await ShowImageDialog ( item ) ;
return ShowImageDialog ( item ) ;
}
return Task . CompletedTask ;
}
public async Task ShowImageDialog ( OutputImageViewModel item )
@ -265,14 +282,13 @@ public partial class OutputsPageViewModel : PageViewModelBase
await vm . GetDialog ( ) . ShowAsync ( ) ;
}
public async Task CopyImage ( string imagePath )
public Task CopyImage ( string imagePath )
{
var clipboard = App . Clipboard ;
await clipboard . SetFileDataObjectAsync ( imagePath ) ;
return clipboard . SetFileDataObjectAsync ( imagePath ) ;
}
public async Task OpenImage ( string imagePath ) = > await ProcessRunner . OpenFileBrowser ( imagePath ) ;
public Task OpenImage ( string imagePath ) = > ProcessRunner . OpenFileBrowser ( imagePath ) ;
public async Task DeleteImage ( OutputImageViewModel ? item )
{
@ -378,12 +394,114 @@ public partial class OutputsPageViewModel : PageViewModelBase
ClearSelection ( ) ;
}
public async Task ConsolidateImages ( )
{
var stackPanel = new StackPanel ( ) ;
stackPanel . Children . Add (
new TextBlock
{
Text = Resources . Label_ConsolidateExplanation ,
TextWrapping = TextWrapping . Wrap ,
Margin = new Thickness ( 0 , 8 , 0 , 1 6 )
}
) ;
foreach ( var category in Categories )
{
if ( category . Name = = "Shared Output Folder" )
{
continue ;
}
stackPanel . Children . Add (
new CheckBox
{
Content = $"{category.Name} ({category.Path})" ,
IsChecked = true ,
Margin = new Thickness ( 0 , 8 , 0 , 0 ) ,
Tag = category . Path
}
) ;
}
var confirmationDialog = new BetterContentDialog
{
Title = Resources . Label_AreYouSure ,
Content = stackPanel ,
PrimaryButtonText = Resources . Action_Yes ,
SecondaryButtonText = Resources . Action_Cancel ,
DefaultButton = ContentDialogButton . Primary ,
IsSecondaryButtonEnabled = true ,
} ;
var dialogResult = await confirmationDialog . ShowAsync ( ) ;
if ( dialogResult ! = ContentDialogResult . Primary )
return ;
IsConsolidating = true ;
Directory . CreateDirectory ( settingsManager . ConsolidatedImagesDirectory ) ;
foreach (
var category in stackPanel . Children . OfType < CheckBox > ( ) . Where ( c = > c . IsChecked = = true )
)
{
if (
string . IsNullOrWhiteSpace ( category . Tag ? . ToString ( ) )
| | ! Directory . Exists ( category . Tag ? . ToString ( ) )
)
continue ;
var directory = category . Tag . ToString ( ) ;
foreach (
var path in Directory . EnumerateFiles (
directory ,
"*.png" ,
SearchOption . AllDirectories
)
)
{
try
{
var file = new FilePath ( path ) ;
var newPath = settingsManager . ConsolidatedImagesDirectory + file . Name ;
if ( file . FullPath = = newPath )
continue ;
// ignore inference if not in inference directory
if (
file . FullPath . Contains ( settingsManager . ImagesInferenceDirectory )
& & directory ! = settingsManager . ImagesInferenceDirectory
)
{
continue ;
}
await file . MoveToAsync ( newPath ) ;
}
catch ( Exception e )
{
logger . LogError ( e , "Error when consolidating: " ) ;
}
}
}
OnLoaded ( ) ;
IsConsolidating = false ;
}
private void GetOutputs ( string directory )
{
if ( ! settingsManager . IsLibraryDirSet )
return ;
if ( ! Directory . Exists ( directory ) & & SelectedOutputType ! = SharedOutputType . All )
if (
! Directory . Exists ( directory )
& & (
SelectedCategory . Path ! = settingsManager . ImagesDirectory
| | SelectedOutputType ! = SharedOutputType . All
)
)
{
Directory . CreateDirectory ( directory ) ;
return ;
@ -391,8 +509,16 @@ public partial class OutputsPageViewModel : PageViewModelBase
var files = Directory
. EnumerateFiles ( directory , "*.png" , SearchOption . AllDirectories )
. Select ( file = > LocalImageFile . FromPath ( file ) ) ;
. Select ( file = > LocalImageFile . FromPath ( file ) )
. ToList ( ) ;
OutputsCache . EditDiff ( files ) ;
if ( files . Count = = 0 )
{
OutputsCache . Clear ( ) ;
}
else
{
OutputsCache . EditDiff ( files ) ;
}
}
}