RootDrives WIP
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
using FileTime.App.Core.Services;
|
||||
|
||||
namespace FileTime.GuiApp.Services;
|
||||
|
||||
public class LifecycleService
|
||||
{
|
||||
private readonly IEnumerable<IExitHandler> _exitHandlers;
|
||||
|
||||
public LifecycleService(IEnumerable<IStartupHandler> startupHandlers, IEnumerable<IExitHandler> exitHandlers)
|
||||
{
|
||||
_exitHandlers = exitHandlers;
|
||||
}
|
||||
|
||||
public async Task Exit()
|
||||
{
|
||||
foreach (var exitHandler in _exitHandlers)
|
||||
{
|
||||
await exitHandler.ExitAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
using System.Reactive.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using DynamicData;
|
||||
using FileTime.App.Core.Models;
|
||||
using FileTime.App.Core.Services;
|
||||
using FileTime.Core.Models;
|
||||
using FileTime.GuiApp.ViewModels;
|
||||
using FileTime.Providers.Local;
|
||||
using IContainer = FileTime.Core.Models.IContainer;
|
||||
|
||||
namespace FileTime.GuiApp.Services;
|
||||
|
||||
public class RootDriveInfoService : IStartupHandler
|
||||
{
|
||||
private readonly SourceList<DriveInfo> _rootDrives = new();
|
||||
|
||||
public RootDriveInfoService(IGuiAppState guiAppState, ILocalContentProvider localContentProvider)
|
||||
{
|
||||
InitRootDrives();
|
||||
|
||||
var rootDriveInfos = Observable.CombineLatest(
|
||||
localContentProvider.Items,
|
||||
_rootDrives.Connect().StartWithEmpty().ToCollection(),
|
||||
(items, drives) =>
|
||||
{
|
||||
return items is null
|
||||
? Observable.Empty<IChangeSet<(IAbsolutePath Path, DriveInfo? Drive)>>()
|
||||
: items
|
||||
.Transform(i => (Path: i, Drive: drives.FirstOrDefault(d =>
|
||||
{
|
||||
var asd1 = localContentProvider.GetNativePath(i.Path).Path;
|
||||
var asd2 = d.Name.TrimEnd(Path.DirectorySeparatorChar);
|
||||
return asd1 == asd2;
|
||||
})))
|
||||
.Filter(t => t.Drive is not null);
|
||||
}
|
||||
)
|
||||
.Switch()
|
||||
.TransformAsync(async t => (Item: await t.Path.ResolveAsyncSafe(), Drive: t.Drive!))
|
||||
.Filter(t => t.Item is IContainer)
|
||||
.Transform(t => (Container: (IContainer)t.Item!, t.Drive))
|
||||
.Transform(t => new RootDriveInfo(t.Drive, t.Container));
|
||||
|
||||
guiAppState.RootDriveInfos = new BindedCollection<RootDriveInfo>(rootDriveInfos);
|
||||
|
||||
void InitRootDrives()
|
||||
{
|
||||
var driveInfos = new List<RootDriveInfo>();
|
||||
IEnumerable<DriveInfo> drives = RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
|
||||
? DriveInfo.GetDrives().Where(d => d.DriveType == DriveType.Fixed)
|
||||
: DriveInfo.GetDrives().Where(d =>
|
||||
d.DriveType == DriveType.Fixed
|
||||
&& d.DriveFormat != "pstorefs"
|
||||
&& d.DriveFormat != "bpf_fs"
|
||||
&& d.DriveFormat != "tracefs"
|
||||
&& !d.RootDirectory.FullName.StartsWith("/snap/"));
|
||||
|
||||
_rootDrives.AddRange(drives);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Reflection;
|
||||
using Avalonia.Input;
|
||||
using FileTime.App.Core;
|
||||
using FileTime.App.Core.Services;
|
||||
using FileTime.App.Core.ViewModels;
|
||||
using FileTime.Core.Models;
|
||||
using FileTime.Core.Services;
|
||||
@@ -19,6 +20,8 @@ namespace FileTime.GuiApp.ViewModels;
|
||||
[Inject(typeof(IServiceProvider), PropertyName = "_serviceProvider")]
|
||||
[Inject(typeof(ILogger<MainWindowViewModel>), PropertyName = "_logger")]
|
||||
[Inject(typeof(IKeyInputHandlerService), PropertyName = "_keyInputHandlerService")]
|
||||
[Inject(typeof(ICommandHandlerService), PropertyAccessModifier = AccessModifier.Public)]
|
||||
[Inject(typeof(LifecycleService), PropertyName = "_lifecycleService")]
|
||||
public partial class MainWindowViewModel : IMainWindowViewModelBase
|
||||
{
|
||||
public bool Loading => false;
|
||||
|
||||
@@ -26,11 +26,12 @@
|
||||
|
||||
<Grid Background="{DynamicResource AppBackgroundBrush}">
|
||||
<Grid
|
||||
x:DataType="vm:MainWindowViewModel"
|
||||
IsVisible="{Binding Loading, Converter={x:Static BoolConverters.Not}}">
|
||||
x:DataType="vm:MainWindowViewModel">
|
||||
<Grid
|
||||
ColumnDefinitions="250,*"
|
||||
RowDefinitions="Auto,*">
|
||||
RowDefinitions="Auto,*"
|
||||
IsVisible="{Binding Loading, Converter={x:Static BoolConverters.Not}}">
|
||||
|
||||
<Grid PointerPressed="HeaderPointerPressed">
|
||||
<Rectangle Fill="#01000000" />
|
||||
<TextBlock
|
||||
@@ -53,6 +54,179 @@
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
|
||||
<Grid Grid.Row="1" RowDefinitions="Auto,Auto,Auto,Auto">
|
||||
|
||||
<Border CornerRadius="10" Background="{DynamicResource ContainerBackgroundBrush}" Padding="10" Margin="10">
|
||||
<Grid RowDefinitions="Auto,Auto">
|
||||
|
||||
<TextBlock
|
||||
Margin="0,0,0,10"
|
||||
Text="Drives" />
|
||||
|
||||
<ItemsRepeater
|
||||
Grid.Row="1"
|
||||
Items="{Binding AppState.RootDriveInfos.Collection}">
|
||||
<ItemsRepeater.ItemTemplate>
|
||||
<DataTemplate x:DataType="vm:RootDriveInfo">
|
||||
<Grid Classes="SidebarContainerPresenter" PointerPressed="OnHasContainerPointerPressed" Cursor="Hand">
|
||||
<Grid Margin="0,5" ColumnDefinitions="Auto,*,Auto" RowDefinitions="Auto,Auto">
|
||||
<Image
|
||||
Grid.RowSpan="2"
|
||||
Width="20"
|
||||
Height="20"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
Source="{SvgImage /Assets/material/folder.svg}" />
|
||||
|
||||
<StackPanel
|
||||
Grid.Column="1"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Stretch"
|
||||
Orientation="Horizontal">
|
||||
|
||||
<TextBlock
|
||||
Margin="5,0,0,0"
|
||||
VerticalAlignment="Center"
|
||||
Text="{Binding FullName}" />
|
||||
|
||||
<TextBlock
|
||||
Margin="5,0,0,0"
|
||||
VerticalAlignment="Center"
|
||||
Classes="ExtraSmallText"
|
||||
Text="{Binding Label}" IsVisible="{Binding Label,Converter={x:Static StringConverters.IsNotNullOrEmpty}}" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel
|
||||
HorizontalAlignment="Right"
|
||||
Grid.Column="2"
|
||||
Orientation="Horizontal"
|
||||
VerticalAlignment="Center">
|
||||
|
||||
<TextBlock Classes="SmallText" VerticalAlignment="Center" Text="{Binding Free, Converter={StaticResource FormatSizeConverter}, ConverterParameter=0}">
|
||||
</TextBlock>
|
||||
|
||||
<TextBlock Classes="SmallText" VerticalAlignment="Center" Text=" / ">
|
||||
</TextBlock>
|
||||
|
||||
<TextBlock Classes="SmallText" VerticalAlignment="Center" Text="{Binding Size, Converter={StaticResource FormatSizeConverter}, ConverterParameter=0}">
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
|
||||
<ProgressBar
|
||||
Margin="5,0,0,0"
|
||||
Grid.Column="1"
|
||||
Grid.ColumnSpan="2"
|
||||
Grid.Row="1"
|
||||
MinWidth="100"
|
||||
HorizontalAlignment="Stretch"
|
||||
Maximum="100"
|
||||
Value="{Binding UsedPercentage}" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ItemsRepeater.ItemTemplate>
|
||||
</ItemsRepeater>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<!--Border Grid.Row="1" CornerRadius="10" Background="{DynamicResource ContainerBackgroundBrush}" Padding="0,10" Margin="10">
|
||||
<Grid RowDefinitions="Auto,Auto">
|
||||
|
||||
<TextBlock
|
||||
Margin="10,0,10,10"
|
||||
Text="Places" />
|
||||
|
||||
<ItemsRepeater
|
||||
Grid.Row="1"
|
||||
Items="{Binding Places}">
|
||||
<ItemsRepeater.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Grid Classes="SidebarContainerPresenter" PointerPressed="OnHasContainerPointerPressed" Cursor="Hand">
|
||||
<StackPanel Orientation="Horizontal" Margin="10,5" HorizontalAlignment="Stretch">
|
||||
<Image
|
||||
Width="20"
|
||||
Height="20"
|
||||
VerticalAlignment="Center"
|
||||
Source="{Binding Container,Converter={StaticResource ItemToImageConverter}}" />
|
||||
|
||||
<TextBlock
|
||||
Margin="5,0,0,0"
|
||||
VerticalAlignment="Center"
|
||||
Text="{Binding Name}" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ItemsRepeater.ItemTemplate>
|
||||
</ItemsRepeater>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<Border Grid.Row="2" CornerRadius="10" Background="{DynamicResource ContainerBackgroundBrush}" Padding="0,10" Margin="10">
|
||||
<Grid RowDefinitions="Auto,Auto">
|
||||
|
||||
<TextBlock
|
||||
Margin="10,0,10,10"
|
||||
Text="Favorites" />
|
||||
|
||||
<ItemsRepeater
|
||||
Grid.Row="1"
|
||||
Items="{Binding AppState.FavoriteElements}">
|
||||
<ItemsRepeater.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Grid Classes="SidebarContainerPresenter" PointerPressed="OnHasContainerPointerPressed" Cursor="Hand">
|
||||
<StackPanel Orientation="Horizontal" Margin="10,5" HorizontalAlignment="Stretch">
|
||||
<Image
|
||||
Width="20"
|
||||
Height="20"
|
||||
VerticalAlignment="Center"
|
||||
Source="{Binding Converter={StaticResource ItemToImageConverter}}" />
|
||||
|
||||
<TextBlock
|
||||
Margin="5,0,0,0"
|
||||
VerticalAlignment="Center"
|
||||
Text="{Binding Name}" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ItemsRepeater.ItemTemplate>
|
||||
</ItemsRepeater>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<Border Grid.Row="3" CornerRadius="10" Background="{DynamicResource ContainerBackgroundBrush}" Padding="0,10" Margin="10">
|
||||
<Grid RowDefinitions="Auto,Auto">
|
||||
|
||||
<TextBlock
|
||||
Margin="10,0,10,10"
|
||||
Text="History" />
|
||||
|
||||
<ItemsRepeater
|
||||
Grid.Row="1"
|
||||
Items="{Binding AppState.SelectedTab.History}">
|
||||
<ItemsRepeater.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Grid Classes="SidebarContainerPresenter" PointerPressed="OnHasContainerPointerPressed" Cursor="Hand">
|
||||
<StackPanel Orientation="Horizontal" Margin="10,5" HorizontalAlignment="Stretch">
|
||||
<Image
|
||||
Width="20"
|
||||
Height="20"
|
||||
VerticalAlignment="Center"
|
||||
Source="{Binding Container,Converter={StaticResource ItemToImageConverter}}" />
|
||||
|
||||
<TextBlock
|
||||
Margin="5,0,0,0"
|
||||
VerticalAlignment="Center"
|
||||
Text="{Binding Name}" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ItemsRepeater.ItemTemplate>
|
||||
</ItemsRepeater>
|
||||
</Grid>
|
||||
</Border-->
|
||||
|
||||
</Grid>
|
||||
|
||||
<Grid
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
using System;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using Avalonia.Threading;
|
||||
using FileTime.Core.Models;
|
||||
using FileTime.GuiApp.Models;
|
||||
using FileTime.GuiApp.ViewModels;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
@@ -68,4 +71,41 @@ public partial class MainWindow : Window
|
||||
BeginMoveDrag(e);
|
||||
}
|
||||
}
|
||||
|
||||
private async void OnHasContainerPointerPressed(object sender, PointerPressedEventArgs e)
|
||||
{
|
||||
if (!e.Handled
|
||||
&& ViewModel != null
|
||||
&& e.GetCurrentPoint(this).Properties.IsLeftButtonPressed
|
||||
&& sender is StyledElement control)
|
||||
{
|
||||
IAbsolutePath? path = null;
|
||||
if (control.DataContext is IHaveAbsolutePath {Path: { }} haveAbsolutePath)
|
||||
{
|
||||
path = haveAbsolutePath.Path;
|
||||
}
|
||||
else if (control.DataContext is IAbsolutePath p)
|
||||
{
|
||||
path = p;
|
||||
}
|
||||
/*else if (control.DataContext is IElement element && element.GetParent() is IContainer parentContainer)
|
||||
{
|
||||
Task.Run(async () =>
|
||||
{
|
||||
await Dispatcher.UIThread.InvokeAsync(async () =>
|
||||
{
|
||||
await ViewModel.AppState.SelectedTab.OpenContainer(parentContainer);
|
||||
await ViewModel.AppState.SelectedTab.SetCurrentSelectedItem(element);
|
||||
});
|
||||
});
|
||||
}*/
|
||||
|
||||
if (path is null) return;
|
||||
|
||||
var resolvedItem = await path.ResolveAsync();
|
||||
if (resolvedItem is not IContainer resolvedContainer) return;
|
||||
//ViewModel.CommandHandlerService.HandleCommandAsync()
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user