Add ability to delete files
This commit is contained in:
Родитель
af17f41c79
Коммит
51b57574e0
|
@ -104,6 +104,7 @@
|
|||
</Grid>
|
||||
<Grid Grid.Row="2">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
|
@ -114,16 +115,20 @@
|
|||
Classes="Rounded"
|
||||
IsVisible="{Binding CanLogout}"
|
||||
Command="{Binding Logout}" />
|
||||
<StackPanel Grid.Column="1" Orientation="Horizontal" Margin="10">
|
||||
<Button Grid.Column="1"
|
||||
Content="Delete"
|
||||
Classes="Rounded"
|
||||
Command="{Binding DeleteSelectedFile}" />
|
||||
<StackPanel Grid.Column="2" Orientation="Horizontal" Margin="10">
|
||||
<TextBlock Text="You selected: " Foreground="#aaaaaa" />
|
||||
<TextBlock Text="{Binding SelectedFile.Name}"
|
||||
Foreground="#888888" />
|
||||
</StackPanel>
|
||||
<Button Grid.Column="2"
|
||||
<Button Grid.Column="3"
|
||||
Content="Upload"
|
||||
Classes="Rounded"
|
||||
Command="{Binding UploadToCurrentPath}" />
|
||||
<Button Grid.Column="3"
|
||||
<Button Grid.Column="4"
|
||||
Content="Download"
|
||||
Classes="Rounded"
|
||||
Command="{Binding DownloadSelectedFile}" />
|
||||
|
|
|
@ -47,9 +47,7 @@ namespace Camelotia.Presentation.Tests
|
|||
|
||||
foreach (var model in real)
|
||||
expected.Should().Contain(drive =>
|
||||
model.Name == drive.Name &&
|
||||
model.IsFolder == false &&
|
||||
model.IsDrive);
|
||||
model.Name == drive.Name && model.IsFolder);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
|
@ -95,7 +95,7 @@ namespace Camelotia.Presentation.Tests
|
|||
[Fact]
|
||||
public void ShouldBeAbleToOpenSelectedPath() => new TestScheduler().With(scheduler =>
|
||||
{
|
||||
var file = new FileModel("foo", Separator + "foo", true, false, string.Empty);
|
||||
var file = new FileModel("foo", Separator + "foo", true, string.Empty);
|
||||
_provider.Get(Separator).Returns(Enumerable.Repeat(file, 1));
|
||||
_authViewModel.IsAuthenticated.Returns(true);
|
||||
_provider.InitialPath.Returns(Separator);
|
||||
|
|
|
@ -115,6 +115,7 @@
|
|||
</Grid>
|
||||
<Grid Grid.Row="2">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
|
@ -124,16 +125,19 @@
|
|||
Style="{StaticResource ButtonRevealStyle}"
|
||||
Visibility="{x:Bind ViewModel.CanLogout, Mode=OneWay}"
|
||||
Command="{x:Bind ViewModel.Logout, Mode=OneWay}" />
|
||||
<StackPanel Grid.Column="1" Orientation="Horizontal" Margin="10">
|
||||
<Button Grid.Column="1" Content="Delete" Margin="0 0 3 0"
|
||||
Style="{StaticResource ButtonRevealStyle}"
|
||||
Command="{x:Bind ViewModel.DeleteSelectedFile, Mode=OneWay}" />
|
||||
<StackPanel Grid.Column="2" Orientation="Horizontal" Margin="10">
|
||||
<TextBlock Text="You selected:" Margin="0 0 3 0" TextTrimming="CharacterEllipsis"
|
||||
Foreground="{ThemeResource ApplicationSecondaryForegroundThemeBrush}" />
|
||||
<TextBlock Text="{x:Bind ViewModel.SelectedFile.Name, Mode=OneWay}"
|
||||
Foreground="{ThemeResource AppBarSeparatorForegroundThemeBrush}" />
|
||||
</StackPanel>
|
||||
<Button Grid.Column="2" Content="Upload" Margin="6 6 0 6"
|
||||
<Button Grid.Column="3" Content="Upload" Margin="6 6 0 6"
|
||||
Style="{StaticResource ButtonRevealStyle}"
|
||||
Command="{x:Bind ViewModel.UploadToCurrentPath, Mode=OneWay}" />
|
||||
<Button Grid.Column="3" Content="Download" Margin="6"
|
||||
<Button Grid.Column="4" Content="Download" Margin="6"
|
||||
Style="{StaticResource ButtonRevealStyle}"
|
||||
Command="{x:Bind ViewModel.DownloadSelectedFile, Mode=OneWay}" />
|
||||
</Grid>
|
||||
|
|
|
@ -16,7 +16,9 @@ namespace Camelotia.Presentation.Interfaces
|
|||
ICommand DownloadSelectedFile { get; }
|
||||
|
||||
ICommand UploadToCurrentPath { get; }
|
||||
|
||||
|
||||
ICommand DeleteSelectedFile { get; }
|
||||
|
||||
ICommand Refresh { get; }
|
||||
|
||||
ICommand Logout { get; }
|
||||
|
|
|
@ -24,6 +24,7 @@ namespace Camelotia.Presentation.ViewModels
|
|||
private readonly ObservableAsPropertyHelper<bool> _isCurrentPathEmpty;
|
||||
private readonly ReactiveCommand<Unit, Unit> _downloadSelectedFile;
|
||||
private readonly ReactiveCommand<Unit, Unit> _uploadToCurrentPath;
|
||||
private readonly ReactiveCommand<Unit, Unit> _deleteSelectedFile;
|
||||
private readonly ObservableAsPropertyHelper<string> _currentPath;
|
||||
private readonly ObservableAsPropertyHelper<bool> _hasErrors;
|
||||
private readonly ObservableAsPropertyHelper<bool> _isLoading;
|
||||
|
@ -66,7 +67,7 @@ namespace Camelotia.Presentation.ViewModels
|
|||
|
||||
var canOpenCurrentPath = this
|
||||
.WhenAnyValue(x => x.SelectedFile)
|
||||
.Select(file => file != null && (file.IsFolder || file.IsDrive))
|
||||
.Select(file => file != null && file.IsFolder)
|
||||
.CombineLatest(_refresh.IsExecuting, (folder, busy) => folder && !busy);
|
||||
|
||||
_open = ReactiveCommand.Create(
|
||||
|
@ -123,7 +124,7 @@ namespace Camelotia.Presentation.ViewModels
|
|||
|
||||
var canDownloadSelectedFile = this
|
||||
.WhenAnyValue(x => x.SelectedFile)
|
||||
.Select(file => file != null && !file.IsFolder && !file.IsDrive)
|
||||
.Select(file => file != null && !file.IsFolder)
|
||||
.DistinctUntilChanged();
|
||||
|
||||
_downloadSelectedFile = ReactiveCommand.CreateFromObservable(
|
||||
|
@ -141,7 +142,7 @@ namespace Camelotia.Presentation.ViewModels
|
|||
.Subscribe(Console.WriteLine);
|
||||
|
||||
this.WhenAnyValue(x => x.SelectedFile)
|
||||
.Where(file => file != null && (file.IsFolder || file.IsDrive))
|
||||
.Where(file => file != null && file.IsFolder)
|
||||
.Buffer(2, 1)
|
||||
.Select(files => (files.First().Path, files.Last().Path))
|
||||
.DistinctUntilChanged()
|
||||
|
@ -159,6 +160,16 @@ namespace Camelotia.Presentation.ViewModels
|
|||
_logout = ReactiveCommand.CreateFromTask(provider.Logout, canLogout);
|
||||
_canLogout = canLogout
|
||||
.ToProperty(this, x => x.CanLogout, scheduler: currentThread);
|
||||
|
||||
var canDeleteSelection = this
|
||||
.WhenAnyValue(x => x.SelectedFile)
|
||||
.Select(file => file != null && !file.IsFolder);
|
||||
|
||||
_deleteSelectedFile = ReactiveCommand.CreateFromTask(
|
||||
() => provider.Delete(SelectedFile),
|
||||
canDeleteSelection);
|
||||
|
||||
_deleteSelectedFile.InvokeCommand(Refresh);
|
||||
|
||||
Auth = authViewModel;
|
||||
Activator = new ViewModelActivator();
|
||||
|
@ -183,7 +194,9 @@ namespace Camelotia.Presentation.ViewModels
|
|||
public ICommand DownloadSelectedFile => _downloadSelectedFile;
|
||||
|
||||
public ICommand UploadToCurrentPath => _uploadToCurrentPath;
|
||||
|
||||
|
||||
public ICommand DeleteSelectedFile => _deleteSelectedFile;
|
||||
|
||||
public bool IsCurrentPathEmpty => _isCurrentPathEmpty.Value;
|
||||
|
||||
public IEnumerable<FileModel> Files => _files.Value;
|
||||
|
|
|
@ -22,6 +22,8 @@ namespace Camelotia.Services.Interfaces
|
|||
|
||||
Task DownloadFile(string from, Stream to);
|
||||
|
||||
Task Delete(FileModel file);
|
||||
|
||||
IObservable<bool> IsAuthorized { get; }
|
||||
|
||||
bool SupportsDirectAuth { get; }
|
||||
|
|
|
@ -2,12 +2,11 @@ namespace Camelotia.Services.Models
|
|||
{
|
||||
public sealed class FileModel
|
||||
{
|
||||
public FileModel(string name, string path, bool isFolder, bool isDrive, string size)
|
||||
public FileModel(string name, string path, bool isFolder, string size)
|
||||
{
|
||||
Name = name;
|
||||
Path = path;
|
||||
IsFolder = isFolder;
|
||||
IsDrive = isDrive;
|
||||
Size = size;
|
||||
}
|
||||
|
||||
|
@ -17,8 +16,6 @@ namespace Camelotia.Services.Models
|
|||
|
||||
public bool IsFolder { get; }
|
||||
|
||||
public bool IsDrive { get; }
|
||||
|
||||
public string Size { get; }
|
||||
}
|
||||
}
|
|
@ -20,7 +20,7 @@ namespace Camelotia.Services.Providers
|
|||
public IObservable<bool> IsAuthorized { get; } = Observable.Return(true);
|
||||
|
||||
public bool SupportsDirectAuth => false;
|
||||
|
||||
|
||||
public bool SupportsOAuth => false;
|
||||
|
||||
public string InitialPath => string.Empty;
|
||||
|
@ -38,19 +38,19 @@ namespace Camelotia.Services.Providers
|
|||
var driveQuery = from entity in GetAllDrives()
|
||||
where entity.IsReady
|
||||
let size = ByteConverter.BytesToString(entity.AvailableFreeSpace)
|
||||
select new FileModel(entity.Name, entity.Name, false, true, size);
|
||||
select new FileModel(entity.Name, entity.Name, true, size);
|
||||
return driveQuery
|
||||
.ToList()
|
||||
.AsEnumerable();
|
||||
}
|
||||
|
||||
|
||||
if (!Directory.Exists(path))
|
||||
throw new ArgumentException("Directory doesn't exist.");
|
||||
|
||||
var query = from entity in Directory.GetFileSystemEntries(path)
|
||||
let isDirectory = IsDirectory(entity)
|
||||
let size = isDirectory ? "*" : ByteConverter.BytesToString(new FileInfo(entity).Length)
|
||||
select new FileModel(Path.GetFileName(entity), entity, isDirectory, false, size);
|
||||
|
||||
var query = from entity in Directory.GetFileSystemEntries(path)
|
||||
let isDirectory = IsDirectory(entity)
|
||||
let size = isDirectory ? "*" : ByteConverter.BytesToString(new FileInfo(entity).Length)
|
||||
select new FileModel(Path.GetFileName(entity), entity, isDirectory, size);
|
||||
|
||||
return query
|
||||
.ToList()
|
||||
|
@ -60,7 +60,7 @@ namespace Camelotia.Services.Providers
|
|||
public async Task DownloadFile(string from, Stream to)
|
||||
{
|
||||
if (IsDirectory(from)) throw new InvalidOperationException("Can't download directory.");
|
||||
|
||||
|
||||
using (var fileStream = File.OpenRead(from))
|
||||
{
|
||||
fileStream.Seek(0, SeekOrigin.Begin);
|
||||
|
@ -71,7 +71,7 @@ namespace Camelotia.Services.Providers
|
|||
public async Task UploadFile(string to, Stream from, string name)
|
||||
{
|
||||
if (!IsDirectory(to)) throw new InvalidOperationException("Can't upload to a non-directory.");
|
||||
|
||||
|
||||
var path = Path.Combine(to, name);
|
||||
using (var fileStream = File.Create(path))
|
||||
{
|
||||
|
@ -80,6 +80,13 @@ namespace Camelotia.Services.Providers
|
|||
}
|
||||
}
|
||||
|
||||
public Task Delete(FileModel file) => Task.Run(() =>
|
||||
{
|
||||
var isDirectory = IsDirectory(file.Path);
|
||||
if (isDirectory) Directory.Delete(file.Path, false);
|
||||
else File.Delete(file.Path);
|
||||
});
|
||||
|
||||
private static string GetSizeOnAllDisks()
|
||||
{
|
||||
var totalBytes = GetAllDrives()
|
||||
|
|
|
@ -14,6 +14,7 @@ using VkNet.Enums.Filters;
|
|||
using VkNet.Model;
|
||||
using VkNet;
|
||||
using VkNet.Abstractions;
|
||||
using VkNet.Model.Attachments;
|
||||
|
||||
namespace Camelotia.Services.Providers
|
||||
{
|
||||
|
@ -78,19 +79,31 @@ namespace Camelotia.Services.Providers
|
|||
var size = string.Empty;
|
||||
if (document.Size.HasValue)
|
||||
size = ByteConverter.BytesToString(document.Size.Value);
|
||||
return new FileModel(document.Title, document.Uri, false, false, size);
|
||||
return new FileModel(document.Title, document.Id.ToString(), false, size);
|
||||
});
|
||||
}
|
||||
|
||||
public async Task DownloadFile(string from, Stream to)
|
||||
{
|
||||
var isValidUriString = Uri.IsWellFormedUriString(from, UriKind.Absolute);
|
||||
var id = long.Parse(from);
|
||||
var users = await _api.Users.GetAsync(new long[0]);
|
||||
var currentUser = users.First();
|
||||
|
||||
var documents = await _api.Docs.GetByIdAsync(new[] {new Document {Id = id, OwnerId = currentUser.Id}});
|
||||
var document = documents.First();
|
||||
Console.WriteLine (document.Uri);
|
||||
|
||||
var uri = document.Uri;
|
||||
var isValidUriString = Uri.IsWellFormedUriString(uri, UriKind.Absolute);
|
||||
if (!isValidUriString) throw new InvalidOperationException("Uri is invalid.");
|
||||
|
||||
using (var http = new HttpClient())
|
||||
using (var response = await http.GetAsync(from).ConfigureAwait(false))
|
||||
using (var response = await http.GetAsync(uri).ConfigureAwait(false))
|
||||
using (var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false))
|
||||
await stream.CopyToAsync(to).ConfigureAwait(false);
|
||||
|
||||
await to.FlushAsync();
|
||||
to.Close();
|
||||
}
|
||||
|
||||
public async Task UploadFile(string to, Stream from, string name)
|
||||
|
@ -111,7 +124,15 @@ namespace Camelotia.Services.Providers
|
|||
|
||||
var error = $"Unable to upload {name}{ext} \n{message}";
|
||||
throw new Exception(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async Task Delete(FileModel file)
|
||||
{
|
||||
var id = long.Parse(file.Path);
|
||||
var users = await _api.Users.GetAsync(new long[0]);
|
||||
var currentUser = users.First();
|
||||
await _api.Docs.DeleteAsync(currentUser.Id, id);
|
||||
}
|
||||
|
||||
private async void EnsureLoggedInIfTokenSaved()
|
||||
|
|
|
@ -69,7 +69,6 @@ namespace Camelotia.Services.Providers
|
|||
file.Name,
|
||||
file.Path.Replace("disk:", ""),
|
||||
file.Type == "dir",
|
||||
false,
|
||||
ByteConverter.BytesToString(file.Size)));
|
||||
|
||||
return models;
|
||||
|
@ -113,6 +112,14 @@ namespace Camelotia.Services.Providers
|
|||
}
|
||||
}
|
||||
|
||||
public async Task Delete(FileModel file)
|
||||
{
|
||||
var encodedPath = WebUtility.UrlEncode(file.Path);
|
||||
var pathUrl = CloudApiGetPathBase + encodedPath;
|
||||
using (var response = await _http.DeleteAsync(pathUrl).ConfigureAwait(false))
|
||||
response.EnsureSuccessStatusCode();
|
||||
}
|
||||
|
||||
public async Task Logout()
|
||||
{
|
||||
await _tokenStorage.WriteToken<YandexFileSystemProvider>(null);
|
||||
|
|
Загрузка…
Ссылка в новой задаче