Cloud drives
This commit is contained in:
@@ -1,3 +1,4 @@
|
|||||||
|
using System.Collections;
|
||||||
using FileTime.Core.Models;
|
using FileTime.Core.Models;
|
||||||
|
|
||||||
namespace FileTime.Core.Helper;
|
namespace FileTime.Core.Helper;
|
||||||
@@ -33,6 +34,7 @@ public static class PathHelper
|
|||||||
|
|
||||||
return string.Join(Constants.SeparatorChar, commonPathParts);
|
return string.Join(Constants.SeparatorChar, commonPathParts);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string GetCommonPath(string? path1, string? path2)
|
public static string GetCommonPath(string? path1, string? path2)
|
||||||
{
|
{
|
||||||
var path1Parts = path1?.Split(Constants.SeparatorChar) ?? Array.Empty<string>();
|
var path1Parts = path1?.Split(Constants.SeparatorChar) ?? Array.Empty<string>();
|
||||||
@@ -51,4 +53,18 @@ public static class PathHelper
|
|||||||
|
|
||||||
return string.Join(Constants.SeparatorChar, commonPathParts);
|
return string.Join(Constants.SeparatorChar, commonPathParts);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
public static string ReplaceEnvironmentVariablePlaceHolders(string path)
|
||||||
|
{
|
||||||
|
foreach (DictionaryEntry environmentVariable in Environment.GetEnvironmentVariables())
|
||||||
|
{
|
||||||
|
var value = environmentVariable.Value?.ToString();
|
||||||
|
|
||||||
|
if (value is null) continue;
|
||||||
|
|
||||||
|
path = path.Replace($"%{environmentVariable.Key}%", value, StringComparison.OrdinalIgnoreCase);
|
||||||
|
}
|
||||||
|
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
namespace FileTime.Core.Models;
|
|
||||||
|
|
||||||
public interface ISymlinkElement
|
|
||||||
{
|
|
||||||
IItem RealItem { get; }
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
using FileTime.Core.Models;
|
||||||
|
|
||||||
|
namespace FileTime.GuiApp.App.CloudDrives;
|
||||||
|
|
||||||
|
public record CloudDrive(string Name, NativePath Path);
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
using FileTime.App.Core.Services;
|
||||||
|
|
||||||
|
namespace FileTime.GuiApp.App.CloudDrives;
|
||||||
|
|
||||||
|
public interface ICloudDriveService : IStartupHandler
|
||||||
|
{
|
||||||
|
IReadOnlyList<CloudDrive> CloudDrives { get; }
|
||||||
|
}
|
||||||
@@ -28,4 +28,5 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -6,5 +6,6 @@ namespace FileTime.GuiApp.App.IconProviders;
|
|||||||
public interface IIconProvider
|
public interface IIconProvider
|
||||||
{
|
{
|
||||||
ImagePath GetImage(IItem item);
|
ImagePath GetImage(IItem item);
|
||||||
|
ImagePath GetImage(string? localPath, bool isContainer, bool isLocalItem);
|
||||||
bool EnableAdvancedIcons { get; set; }
|
bool EnableAdvancedIcons { get; set; }
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
using PropertyChanged.SourceGenerator;
|
||||||
|
|
||||||
|
namespace FileTime.GuiApp.App.CloudDrives;
|
||||||
|
|
||||||
|
public partial class LinuxCloudDriveService : ICloudDriveService
|
||||||
|
{
|
||||||
|
[Notify] private IReadOnlyList<CloudDrive> _cloudDrives = new List<CloudDrive>();
|
||||||
|
|
||||||
|
public Task InitAsync() => Task.CompletedTask;
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
// Based on: https://github.com/files-community/Files/blob/main/src/Files.App/Utils/Cloud/CloudDrivesDetector.cs
|
||||||
|
|
||||||
|
using System.Runtime.Versioning;
|
||||||
|
using FileTime.Core.Helper;
|
||||||
|
using FileTime.Core.Models;
|
||||||
|
using Microsoft.Win32;
|
||||||
|
using PropertyChanged.SourceGenerator;
|
||||||
|
|
||||||
|
namespace FileTime.GuiApp.App.CloudDrives;
|
||||||
|
|
||||||
|
[SupportedOSPlatform("windows")]
|
||||||
|
public sealed partial class WindowsCloudDriveService : ICloudDriveService
|
||||||
|
{
|
||||||
|
[Notify] private IReadOnlyList<CloudDrive> _cloudDrives = new List<CloudDrive>();
|
||||||
|
|
||||||
|
private async Task<List<CloudDrive>> GetCloudDrives()
|
||||||
|
{
|
||||||
|
var cloudDrives = new List<CloudDrive>();
|
||||||
|
cloudDrives.AddRange(await GetOneDrive());
|
||||||
|
cloudDrives.Sort((x, y) => string.Compare(x.Name, y.Name, StringComparison.Ordinal));
|
||||||
|
return cloudDrives;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Task<IEnumerable<CloudDrive>> GetOneDrive()
|
||||||
|
{
|
||||||
|
using var oneDriveAccountsKey = Registry.CurrentUser.OpenSubKey(@"SOFTWARE\Microsoft\OneDrive\Accounts");
|
||||||
|
if (oneDriveAccountsKey is null)
|
||||||
|
{
|
||||||
|
return Task.FromResult(Enumerable.Empty<CloudDrive>());
|
||||||
|
}
|
||||||
|
|
||||||
|
var oneDriveAccounts = new List<CloudDrive>();
|
||||||
|
foreach (var account in oneDriveAccountsKey.GetSubKeyNames())
|
||||||
|
{
|
||||||
|
var accountKeyName = @$"{oneDriveAccountsKey.Name}\{account}";
|
||||||
|
var displayName = (string?) Registry.GetValue(accountKeyName, "DisplayName", null);
|
||||||
|
var userFolder = (string?) Registry.GetValue(accountKeyName, "UserFolder", null);
|
||||||
|
var accountName = string.IsNullOrWhiteSpace(displayName) ? "OneDrive" : $"OneDrive - {displayName}";
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(userFolder) || oneDriveAccounts.Any(x => x.Name == accountName)) continue;
|
||||||
|
|
||||||
|
userFolder = PathHelper.ReplaceEnvironmentVariablePlaceHolders(userFolder);
|
||||||
|
|
||||||
|
oneDriveAccounts.Add(new CloudDrive(accountName, new NativePath(userFolder)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Task.FromResult<IEnumerable<CloudDrive>>(oneDriveAccounts);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task InitAsync() => CloudDrives = (await GetCloudDrives()).AsReadOnly();
|
||||||
|
}
|
||||||
@@ -4,40 +4,34 @@ using Avalonia.Svg.Skia;
|
|||||||
using FileTime.App.Core.ViewModels;
|
using FileTime.App.Core.ViewModels;
|
||||||
using FileTime.Core.Models;
|
using FileTime.Core.Models;
|
||||||
using FileTime.GuiApp.App.IconProviders;
|
using FileTime.GuiApp.App.IconProviders;
|
||||||
|
using FileTime.GuiApp.App.Models;
|
||||||
|
using FileTime.Providers.Local;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
namespace FileTime.GuiApp.App.Converters;
|
namespace FileTime.GuiApp.App.Converters;
|
||||||
|
|
||||||
public class ItemToImageConverter : IValueConverter
|
public class ItemToImageConverter : IValueConverter
|
||||||
{
|
{
|
||||||
private readonly IIconProvider _iconProvider;
|
private readonly IIconProvider _iconProvider = DI.ServiceProvider.GetRequiredService<IIconProvider>();
|
||||||
|
private readonly ILocalContentProvider _localContentProvider = DI.ServiceProvider.GetRequiredService<ILocalContentProvider>();
|
||||||
public ItemToImageConverter()
|
|
||||||
{
|
|
||||||
_iconProvider = DI.ServiceProvider.GetRequiredService<IIconProvider>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
|
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||||
{
|
{
|
||||||
if (value == null) return null;
|
if (value == null) return null;
|
||||||
|
|
||||||
IItem item = value switch
|
|
||||||
{
|
|
||||||
IContainerViewModel container => container.Container!,
|
|
||||||
IElementViewModel element => element.Element!,
|
|
||||||
IItem i => i,
|
|
||||||
_ => throw new NotImplementedException()
|
|
||||||
};
|
|
||||||
|
|
||||||
SvgSource? source;
|
SvgSource? source;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var path = _iconProvider.GetImage(item)!;
|
var path = GetImageFromPath(value);
|
||||||
if (path.Type == Models.ImagePathType.Absolute)
|
path ??= GetImageFromItem(value);
|
||||||
|
|
||||||
|
if (path is null) return null;
|
||||||
|
|
||||||
|
if (path.Type == ImagePathType.Absolute)
|
||||||
{
|
{
|
||||||
source = SvgSource.Load<SvgSource>(path.Path!, null);
|
source = SvgSource.Load<SvgSource>(path.Path!, null);
|
||||||
}
|
}
|
||||||
else if (path.Type == Models.ImagePathType.Raw)
|
else if (path.Type == ImagePathType.Raw)
|
||||||
{
|
{
|
||||||
return path.Image;
|
return path.Image;
|
||||||
}
|
}
|
||||||
@@ -54,6 +48,35 @@ public class ItemToImageConverter : IValueConverter
|
|||||||
return new SvgImage {Source = source};
|
return new SvgImage {Source = source};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ImagePath? GetImageFromItem(object value)
|
||||||
|
{
|
||||||
|
var item = value switch
|
||||||
|
{
|
||||||
|
IContainerViewModel container => container.Container!,
|
||||||
|
IElementViewModel element => element.Element!,
|
||||||
|
IItem i => i,
|
||||||
|
_ => null
|
||||||
|
};
|
||||||
|
|
||||||
|
if (item is null) return null;
|
||||||
|
|
||||||
|
return _iconProvider.GetImage(item)!;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ImagePath? GetImageFromPath(object value)
|
||||||
|
{
|
||||||
|
if (value is not NativePath nativePath) return null;
|
||||||
|
|
||||||
|
var canHandlePathTask = _localContentProvider.CanHandlePathAsync(nativePath);
|
||||||
|
canHandlePathTask.Wait();
|
||||||
|
var isLocal = canHandlePathTask.Result;
|
||||||
|
|
||||||
|
|
||||||
|
var isDirectory = Directory.Exists(nativePath.Path);
|
||||||
|
|
||||||
|
return _iconProvider.GetImage(nativePath.Path, isDirectory, isLocal);
|
||||||
|
}
|
||||||
|
|
||||||
public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
|
public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
|
|||||||
@@ -58,6 +58,7 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -33,32 +33,38 @@ public class MaterialIconProvider : IIconProvider
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public ImagePath GetImage(IItem item)
|
public ImagePath GetImage(IItem item) => GetImage(item.NativePath?.Path, item is IContainer, item.Provider is ILocalContentProvider);
|
||||||
|
|
||||||
|
public ImagePath GetImage(string? localPath, bool isContainer, bool isLocalItem)
|
||||||
{
|
{
|
||||||
item = item is ISymlinkElement symlinkElement ? symlinkElement.RealItem : item;
|
var icon = isContainer ? "folder.svg" : "file.svg";
|
||||||
var icon = item is IContainer ? "folder.svg" : "file.svg";
|
localPath = localPath?.TrimEnd(Path.DirectorySeparatorChar);
|
||||||
var localPath = item.NativePath?.Path.TrimEnd(Path.DirectorySeparatorChar);
|
|
||||||
|
|
||||||
if (!EnableAdvancedIcons) return GetAssetPath(icon);
|
if (!EnableAdvancedIcons) return GetAssetPath(icon);
|
||||||
|
|
||||||
if (localPath != null && _specialPaths.Value.Find(p => p.Path == localPath) is SpecialPathWithIcon specialPath)
|
if (_specialPaths.Value.Find(p => p.Path == localPath) is { } specialPath)
|
||||||
{
|
{
|
||||||
return specialPath.IconPath;
|
return specialPath.IconPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item is not IElement element) return GetAssetPath(icon);
|
if (isContainer || localPath is null) return GetAssetPath(icon);
|
||||||
|
|
||||||
if (element.Provider is ILocalContentProvider && (localPath?.EndsWith(".svg") ?? false))
|
if (isLocalItem && localPath.EndsWith(".svg"))
|
||||||
{
|
{
|
||||||
return new ImagePath(ImagePathType.Absolute, localPath);
|
return new ImagePath(ImagePathType.Absolute, localPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
string? possibleIcon = null;
|
string? possibleIcon;
|
||||||
var fileName = element.Name;
|
var fileName = localPath.Split(Path.DirectorySeparatorChar).Last();
|
||||||
var extension = element.Name.Contains('.') ? element.Name.Split('.').Last() : null;
|
|
||||||
|
|
||||||
if (_iconsByFileName.TryGetValue(fileName, out var value)) possibleIcon = value;
|
if (_iconsByFileName.TryGetValue(fileName, out var value))
|
||||||
else if (_iconsByExtension.FirstOrDefault(k => fileName.EndsWith("." + k.Key)) is KeyValuePair<string, string> {Key: { }} matchingExtension) possibleIcon = matchingExtension.Value;
|
{
|
||||||
|
possibleIcon = value;
|
||||||
|
}
|
||||||
|
else if (_iconsByExtension.FirstOrDefault(k => fileName.EndsWith("." + k.Key)) is var matchingExtension)
|
||||||
|
{
|
||||||
|
possibleIcon = matchingExtension.Value;
|
||||||
|
}
|
||||||
|
|
||||||
if (possibleIcon != null)
|
if (possibleIcon != null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ using FileTime.App.Core.Services;
|
|||||||
using FileTime.App.Core.ViewModels;
|
using FileTime.App.Core.ViewModels;
|
||||||
using FileTime.App.Core.ViewModels.Timeline;
|
using FileTime.App.Core.ViewModels.Timeline;
|
||||||
using FileTime.App.FrequencyNavigation.Services;
|
using FileTime.App.FrequencyNavigation.Services;
|
||||||
|
using FileTime.GuiApp.App.CloudDrives;
|
||||||
using FileTime.GuiApp.App.Services;
|
using FileTime.GuiApp.App.Services;
|
||||||
using FileTime.Providers.LocalAdmin;
|
using FileTime.Providers.LocalAdmin;
|
||||||
|
|
||||||
@@ -21,6 +22,7 @@ public interface IMainWindowViewModel : IMainWindowViewModelBase
|
|||||||
IClipboardService ClipboardService { get; }
|
IClipboardService ClipboardService { get; }
|
||||||
ITimelineViewModel TimelineViewModel { get; }
|
ITimelineViewModel TimelineViewModel { get; }
|
||||||
IPossibleCommandsViewModel PossibleCommands { get; }
|
IPossibleCommandsViewModel PossibleCommands { get; }
|
||||||
|
ICloudDriveService CloudDriveService { get; }
|
||||||
Action? ShowWindow { get; set; }
|
Action? ShowWindow { get; set; }
|
||||||
Thickness IconStatusPanelMargin { get; }
|
Thickness IconStatusPanelMargin { get; }
|
||||||
Task RunOrOpenItem(IItemViewModel itemViewModel);
|
Task RunOrOpenItem(IItemViewModel itemViewModel);
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ using FileTime.App.Core.ViewModels.Timeline;
|
|||||||
using FileTime.App.FrequencyNavigation.Services;
|
using FileTime.App.FrequencyNavigation.Services;
|
||||||
using FileTime.Core.Models;
|
using FileTime.Core.Models;
|
||||||
using FileTime.Core.Timeline;
|
using FileTime.Core.Timeline;
|
||||||
|
using FileTime.GuiApp.App.CloudDrives;
|
||||||
using FileTime.GuiApp.App.InstanceManagement;
|
using FileTime.GuiApp.App.InstanceManagement;
|
||||||
using FileTime.GuiApp.App.Services;
|
using FileTime.GuiApp.App.Services;
|
||||||
using FileTime.Providers.Local;
|
using FileTime.Providers.Local;
|
||||||
@@ -43,6 +44,7 @@ namespace FileTime.GuiApp.App.ViewModels;
|
|||||||
[Inject(typeof(ITimelineViewModel), PropertyAccessModifier = AccessModifier.Public)]
|
[Inject(typeof(ITimelineViewModel), PropertyAccessModifier = AccessModifier.Public)]
|
||||||
[Inject(typeof(IPossibleCommandsViewModel), PropertyName = "PossibleCommands", PropertyAccessModifier = AccessModifier.Public)]
|
[Inject(typeof(IPossibleCommandsViewModel), PropertyName = "PossibleCommands", PropertyAccessModifier = AccessModifier.Public)]
|
||||||
[Inject(typeof(IInstanceMessageHandler), PropertyName = "_instanceMessageHandler")]
|
[Inject(typeof(IInstanceMessageHandler), PropertyName = "_instanceMessageHandler")]
|
||||||
|
[Inject(typeof(ICloudDriveService), PropertyAccessModifier = AccessModifier.Public)]
|
||||||
public partial class MainWindowViewModel : IMainWindowViewModel
|
public partial class MainWindowViewModel : IMainWindowViewModel
|
||||||
{
|
{
|
||||||
public bool Loading => false;
|
public bool Loading => false;
|
||||||
@@ -57,7 +59,7 @@ public partial class MainWindowViewModel : IMainWindowViewModel
|
|||||||
|
|
||||||
partial void OnInitialize()
|
partial void OnInitialize()
|
||||||
{
|
{
|
||||||
_logger?.LogInformation($"Starting {nameof(MainWindowViewModel)} initialization...");
|
_logger.LogInformation($"Starting {nameof(MainWindowViewModel)} initialization...");
|
||||||
|
|
||||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
xmlns="https://github.com/avaloniaui"
|
xmlns="https://github.com/avaloniaui"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:appCoreModels="using:FileTime.App.Core.Models"
|
xmlns:appCoreModels="using:FileTime.App.Core.Models"
|
||||||
|
xmlns:cloudDrives="clr-namespace:FileTime.GuiApp.App.CloudDrives;assembly=FileTime.GuiApp.App.Abstractions"
|
||||||
xmlns:corevm="using:FileTime.App.Core.ViewModels"
|
xmlns:corevm="using:FileTime.App.Core.ViewModels"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:i="clr-namespace:Avalonia.Xaml.Interactivity;assembly=Avalonia.Xaml.Interactivity"
|
xmlns:i="clr-namespace:Avalonia.Xaml.Interactivity;assembly=Avalonia.Xaml.Interactivity"
|
||||||
@@ -116,13 +117,13 @@
|
|||||||
|
|
||||||
<Border
|
<Border
|
||||||
Margin="10"
|
Margin="10"
|
||||||
Padding="10"
|
Padding="0,10"
|
||||||
Background="{DynamicResource ContainerBackgroundBrush}"
|
Background="{DynamicResource ContainerBackgroundBrush}"
|
||||||
CornerRadius="10">
|
CornerRadius="10">
|
||||||
<Grid RowDefinitions="Auto,Auto">
|
<Grid RowDefinitions="Auto,Auto">
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Margin="0,0,0,10"
|
Margin="10,0,10,10"
|
||||||
Text="Drives" />
|
Text="Drives" />
|
||||||
|
|
||||||
<ItemsRepeater
|
<ItemsRepeater
|
||||||
@@ -135,7 +136,7 @@
|
|||||||
Cursor="Hand"
|
Cursor="Hand"
|
||||||
PointerPressed="OnHasContainerPointerPressed">
|
PointerPressed="OnHasContainerPointerPressed">
|
||||||
<Grid
|
<Grid
|
||||||
Margin="0,5"
|
Margin="10,5"
|
||||||
ColumnDefinitions="Auto,*,Auto"
|
ColumnDefinitions="Auto,*,Auto"
|
||||||
RowDefinitions="Auto,Auto">
|
RowDefinitions="Auto,Auto">
|
||||||
<Image
|
<Image
|
||||||
@@ -209,7 +210,8 @@
|
|||||||
Margin="10"
|
Margin="10"
|
||||||
Padding="0,10"
|
Padding="0,10"
|
||||||
Background="{DynamicResource ContainerBackgroundBrush}"
|
Background="{DynamicResource ContainerBackgroundBrush}"
|
||||||
CornerRadius="10">
|
CornerRadius="10"
|
||||||
|
IsVisible="{Binding AppState.Places.Count, Converter={StaticResource GreaterThanConverter}, ConverterParameter=0}">
|
||||||
<Grid RowDefinitions="Auto,Auto">
|
<Grid RowDefinitions="Auto,Auto">
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
@@ -250,6 +252,52 @@
|
|||||||
<Border
|
<Border
|
||||||
Grid.Row="2"
|
Grid.Row="2"
|
||||||
Margin="10"
|
Margin="10"
|
||||||
|
Padding="0,10"
|
||||||
|
VerticalAlignment="Bottom"
|
||||||
|
Background="{DynamicResource ContainerBackgroundBrush}"
|
||||||
|
CornerRadius="10"
|
||||||
|
IsVisible="{Binding CloudDriveService.CloudDrives.Count, Converter={StaticResource GreaterThanConverter}, ConverterParameter=0}">
|
||||||
|
<Grid RowDefinitions="Auto,Auto">
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
Margin="10,0,10,10"
|
||||||
|
Text="Cloud drives" />
|
||||||
|
|
||||||
|
<ItemsRepeater
|
||||||
|
Grid.Row="1"
|
||||||
|
ItemsSource="{Binding CloudDriveService.CloudDrives}">
|
||||||
|
<ItemsRepeater.ItemTemplate>
|
||||||
|
<DataTemplate x:DataType="cloudDrives:CloudDrive">
|
||||||
|
<Grid
|
||||||
|
Classes="SidebarContainerPresenter"
|
||||||
|
Cursor="Hand"
|
||||||
|
PointerPressed="OnHasContainerPointerPressed">
|
||||||
|
<StackPanel
|
||||||
|
Margin="10,5"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
Orientation="Horizontal"
|
||||||
|
ToolTip.Tip="{Binding Name}">
|
||||||
|
<Image
|
||||||
|
Width="20"
|
||||||
|
Height="20"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Source="{Binding Path, 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"
|
||||||
|
Margin="10"
|
||||||
Padding="10"
|
Padding="10"
|
||||||
VerticalAlignment="Bottom"
|
VerticalAlignment="Bottom"
|
||||||
Background="{DynamicResource ContainerBackgroundBrush}"
|
Background="{DynamicResource ContainerBackgroundBrush}"
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ using Avalonia.VisualTree;
|
|||||||
using FileTime.App.Core.Services;
|
using FileTime.App.Core.Services;
|
||||||
using FileTime.App.Core.ViewModels;
|
using FileTime.App.Core.ViewModels;
|
||||||
using FileTime.Core.Models;
|
using FileTime.Core.Models;
|
||||||
|
using FileTime.Core.Timeline;
|
||||||
|
using FileTime.GuiApp.App.CloudDrives;
|
||||||
using FileTime.GuiApp.App.Services;
|
using FileTime.GuiApp.App.Services;
|
||||||
using FileTime.GuiApp.App.Settings;
|
using FileTime.GuiApp.App.Settings;
|
||||||
using FileTime.GuiApp.App.ViewModels;
|
using FileTime.GuiApp.App.ViewModels;
|
||||||
@@ -138,6 +140,11 @@ public partial class MainWindow : Window, IUiAccessor
|
|||||||
{
|
{
|
||||||
path = placeInfoPath;
|
path = placeInfoPath;
|
||||||
}
|
}
|
||||||
|
else if (control.DataContext is CloudDrive {Path: { } cloudDrivePath})
|
||||||
|
{
|
||||||
|
var timelessContentProvider = DI.ServiceProvider.GetRequiredService<ITimelessContentProvider>();
|
||||||
|
path = await timelessContentProvider.GetFullNameByNativePathAsync(cloudDrivePath);
|
||||||
|
}
|
||||||
|
|
||||||
if (path is null) return;
|
if (path is null) return;
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using FileTime.App.Core.Configuration;
|
|||||||
using FileTime.App.Core.Services;
|
using FileTime.App.Core.Services;
|
||||||
using FileTime.App.Core.ViewModels;
|
using FileTime.App.Core.ViewModels;
|
||||||
using FileTime.Core.Interactions;
|
using FileTime.Core.Interactions;
|
||||||
|
using FileTime.GuiApp.App.CloudDrives;
|
||||||
using FileTime.GuiApp.App.Configuration;
|
using FileTime.GuiApp.App.Configuration;
|
||||||
using FileTime.GuiApp.App.ContextMenu;
|
using FileTime.GuiApp.App.ContextMenu;
|
||||||
using FileTime.GuiApp.CustomImpl.ViewModels;
|
using FileTime.GuiApp.CustomImpl.ViewModels;
|
||||||
@@ -84,18 +85,21 @@ public static class Startup
|
|||||||
{
|
{
|
||||||
serviceCollection
|
serviceCollection
|
||||||
.AddSingleton<IContextMenuProvider, WindowsContextMenuProvider>()
|
.AddSingleton<IContextMenuProvider, WindowsContextMenuProvider>()
|
||||||
.AddSingleton<IPlacesService, WindowsPlacesService>();
|
.AddSingleton<IPlacesService, WindowsPlacesService>()
|
||||||
|
.AddSingleton<ICloudDriveService, WindowsCloudDriveService>();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
serviceCollection
|
serviceCollection
|
||||||
.AddSingleton<IContextMenuProvider, LinuxContextMenuProvider>()
|
.AddSingleton<IContextMenuProvider, LinuxContextMenuProvider>()
|
||||||
.AddSingleton<IPlacesService, LinuxPlacesService>();
|
.AddSingleton<IPlacesService, LinuxPlacesService>()
|
||||||
|
.AddSingleton<ICloudDriveService, LinuxCloudDriveService>();
|
||||||
}
|
}
|
||||||
|
|
||||||
return serviceCollection
|
return serviceCollection
|
||||||
.AddSingleton<IExitHandler, RootDriveInfoService>()
|
.AddSingleton<IExitHandler>(sp => sp.GetRequiredService<IRootDriveInfoService>())
|
||||||
.AddSingleton<IStartupHandler>(sp => sp.GetRequiredService<IPlacesService>());
|
.AddSingleton<IStartupHandler>(sp => sp.GetRequiredService<IPlacesService>())
|
||||||
|
.AddSingleton<IStartupHandler>(sp => sp.GetRequiredService<ICloudDriveService>());
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static IServiceCollection RegisterLogging(this IServiceCollection serviceCollection)
|
internal static IServiceCollection RegisterLogging(this IServiceCollection serviceCollection)
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
|
using FileTime.App.Core.Services;
|
||||||
|
|
||||||
namespace FileTime.Providers.Local;
|
namespace FileTime.Providers.Local;
|
||||||
|
|
||||||
public interface IRootDriveInfoService
|
public interface IRootDriveInfoService : IExitHandler
|
||||||
{
|
{
|
||||||
ObservableCollection<RootDriveInfo> RootDriveInfos { get; set; }
|
ObservableCollection<RootDriveInfo> RootDriveInfos { get; set; }
|
||||||
}
|
}
|
||||||
@@ -1,12 +1,11 @@
|
|||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using FileTime.App.Core.Services;
|
|
||||||
using FileTime.Core.Models;
|
using FileTime.Core.Models;
|
||||||
using ObservableComputations;
|
using ObservableComputations;
|
||||||
|
|
||||||
namespace FileTime.Providers.Local;
|
namespace FileTime.Providers.Local;
|
||||||
|
|
||||||
public class RootDriveInfoService : IRootDriveInfoService, IExitHandler
|
public class RootDriveInfoService : IRootDriveInfoService
|
||||||
{
|
{
|
||||||
private readonly ILocalContentProvider _localContentProvider;
|
private readonly ILocalContentProvider _localContentProvider;
|
||||||
private readonly List<DriveInfo> _rootDrives = new();
|
private readonly List<DriveInfo> _rootDrives = new();
|
||||||
|
|||||||
Reference in New Issue
Block a user