diff --git a/Directory.Build.props b/Directory.Build.props
index 31a7bf2b..c61df258 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -9,6 +9,7 @@
https://github.com/jinek/Consolonia/graphs/contributors
Text User Interface implementation of Avalonia UI (GUI Framework)
Copyright Β© Evgeny Gorbovoy 2021 - 2022
+ AVA3001
11.0.9
diff --git a/src/.editorconfig b/src/.editorconfig
index 45b7f78a..dc887c0f 100644
--- a/src/.editorconfig
+++ b/src/.editorconfig
@@ -74,6 +74,7 @@ dotnet_diagnostic.ca1043.severity = none # todo: why not to use indexer rather t
dotnet_diagnostic.ca1814.severity = none # sometimes we need rectangle array
dotnet_diagnostic.ca1058.severity = none # check why new documentation warns not to derive from ApplicationException. The purpose of last is to distinguish system exceptions like OOM, AssemblyLoadException etc from application logic
dotnet_diagnostic.ca2000.severity = none # exceptions which are listed in the rule can be applied to any type
+dotnet_diagnostic.CA2007.severity = none # we are assuming task continuation thread is fine by default
dotnet_diagnostic.ca2213.severity = none # keeping field does not mean necessarity to dispose - it can be dispose somwhere else
dotnet_diagnostic.ca2248.severity = none # https://github.com/dotnet/roslyn-analyzers/issues/4432
dotnet_diagnostic.ca1062.severity = none # we are fine with NRE - no need for additional checks
diff --git a/src/Consolonia.Core/Consolonia.Core.csproj b/src/Consolonia.Core/Consolonia.Core.csproj
index 00b7142a..d059e8af 100644
--- a/src/Consolonia.Core/Consolonia.Core.csproj
+++ b/src/Consolonia.Core/Consolonia.Core.csproj
@@ -1,15 +1,22 @@
-
+
+
+
+
+
+
+
+
+
-
\ No newline at end of file
diff --git a/src/Consolonia.Themes.TurboVision/Templates/Controls/Dialog/DialogHelpers.cs b/src/Consolonia.Core/Controls/Dialog/DialogHelpers.cs
similarity index 98%
rename from src/Consolonia.Themes.TurboVision/Templates/Controls/Dialog/DialogHelpers.cs
rename to src/Consolonia.Core/Controls/Dialog/DialogHelpers.cs
index a7407024..80f6a80c 100644
--- a/src/Consolonia.Themes.TurboVision/Templates/Controls/Dialog/DialogHelpers.cs
+++ b/src/Consolonia.Core/Controls/Dialog/DialogHelpers.cs
@@ -11,7 +11,7 @@
using Avalonia.VisualTree;
using Consolonia.Core.Helpers;
-namespace Consolonia.Themes.TurboVision.Templates.Controls.Dialog
+namespace Consolonia.Core.Controls.Dialog
{
public class DialogHost
{
diff --git a/src/Consolonia.Themes.TurboVision/Templates/Controls/DialogWrap.axaml b/src/Consolonia.Core/Controls/Dialog/DialogWrap.axaml
similarity index 90%
rename from src/Consolonia.Themes.TurboVision/Templates/Controls/DialogWrap.axaml
rename to src/Consolonia.Core/Controls/Dialog/DialogWrap.axaml
index 49501ce7..89fcd51e 100644
--- a/src/Consolonia.Themes.TurboVision/Templates/Controls/DialogWrap.axaml
+++ b/src/Consolonia.Core/Controls/Dialog/DialogWrap.axaml
@@ -1,7 +1,7 @@
+ x:Class="Consolonia.Core.Controls.Dialog.DialogWrap">
IsCloseButtonVisibleProperty =
AvaloniaProperty.Register(nameof(IsCloseButtonVisible), true);
+ public static readonly StyledProperty WindowStartupLocationProperty =
+ AvaloniaProperty.Register(nameof(WindowStartupLocation));
+
+ public static readonly StyledProperty CanResizeProperty =
+ AvaloniaProperty.Register(nameof(CanResize), true);
+
+ public static readonly StyledProperty IconProperty =
+ AvaloniaProperty.Register(nameof(Icon));
+
private Size _contentSize;
private ContentPresenter _partContentPresenter;
- private TaskCompletionSource _taskCompletionSource;
+ private TaskCompletionSource
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/src/Consolonia.Gallery/Gallery/GalleryViews/SomeDialogWindow.axaml.cs b/src/Consolonia.Gallery/Gallery/GalleryViews/SomeDialogWindow.axaml.cs
index 38ef926f..7fa50484 100644
--- a/src/Consolonia.Gallery/Gallery/GalleryViews/SomeDialogWindow.axaml.cs
+++ b/src/Consolonia.Gallery/Gallery/GalleryViews/SomeDialogWindow.axaml.cs
@@ -1,8 +1,6 @@
using System;
-using Avalonia.Controls;
using Avalonia.Interactivity;
-using Avalonia.Markup.Xaml;
-using Consolonia.Themes.TurboVision.Templates.Controls.Dialog;
+using Consolonia.Core.Controls;
namespace Consolonia.Gallery.Gallery.GalleryViews
{
@@ -15,10 +13,7 @@ public SomeDialogWindow(double width, double height)
InitializeComponent();
Width = width;
Height = height;
- Loaded += (_, _) =>
- {
- this.FindControl
+
diff --git a/src/Tests/Consolonia.Core.Tests/StorageTests.cs b/src/Tests/Consolonia.Core.Tests/StorageTests.cs
new file mode 100644
index 00000000..ec85480f
--- /dev/null
+++ b/src/Tests/Consolonia.Core.Tests/StorageTests.cs
@@ -0,0 +1,172 @@
+// ReSharper disable PossibleNullReferenceException
+// ReSharper disable ConstantConditionalAccessQualifier
+
+using System;
+using System.Globalization;
+using System.IO;
+using System.Threading.Tasks;
+using Avalonia.Platform.Storage;
+using Consolonia.Core.Infrastructure;
+using NUnit.Framework;
+
+namespace Consolonia.Core.Tests
+{
+ [TestFixture]
+ public class StorageTests
+ {
+ [Test]
+ public void DefaultAttributes()
+ {
+ var storageProvider = new ConsoloniaStorageProvider();
+ Assert.True(storageProvider.CanOpen);
+ Assert.True(storageProvider.CanSave);
+ Assert.True(storageProvider.CanPickFolder);
+ }
+
+ [Test]
+ public async Task TestFileSemantics()
+ {
+ var storageProvider = new ConsoloniaStorageProvider();
+ string tempFile = Path.GetTempFileName();
+ IStorageFile file = await storageProvider.TryGetFileFromPathAsync(new Uri($"file://{tempFile}"));
+ Assert.IsNotNull(file);
+ Assert.AreEqual(tempFile, file.Path.LocalPath);
+
+ using (Stream stream = await file.OpenWriteAsync())
+ {
+ using (var streamWriter = new StreamWriter(stream))
+ {
+ await streamWriter.WriteAsync("Hello world");
+ }
+ }
+
+ Assert.True(File.Exists(tempFile));
+ Assert.True(File.Exists(file.Path.LocalPath));
+ StorageItemProperties props = await file.GetBasicPropertiesAsync();
+ Assert.AreEqual(File.GetCreationTime(tempFile).ToString("G", CultureInfo.InvariantCulture),
+ props.DateCreated?.DateTime.ToString("G", CultureInfo.InvariantCulture));
+ Assert.AreEqual(File.GetLastWriteTime(tempFile).ToString("G", CultureInfo.InvariantCulture),
+ props.DateModified?.DateTime.ToString("G", CultureInfo.InvariantCulture));
+ Assert.AreEqual(new FileInfo(tempFile).Length, (long)(props.Size ?? 0));
+
+ using (Stream stream = await file.OpenReadAsync())
+ {
+ using (var streamReader = new StreamReader(stream))
+ {
+ string text = await streamReader.ReadToEndAsync();
+ Assert.AreEqual("Hello world", text);
+ }
+ }
+
+ props = await file.GetBasicPropertiesAsync();
+ Assert.AreEqual(File.GetCreationTime(tempFile).ToString("G", CultureInfo.InvariantCulture),
+ props.DateCreated?.DateTime.ToString("G", CultureInfo.InvariantCulture));
+ Assert.AreEqual(File.GetLastWriteTime(tempFile).ToString("G", CultureInfo.InvariantCulture),
+ props.DateModified?.DateTime.ToString("G", CultureInfo.InvariantCulture));
+ Assert.AreEqual(new FileInfo(tempFile).Length, (long)(props.Size ?? 0));
+
+ IStorageFolder parentFolder = await file.GetParentAsync();
+ Assert.IsNotNull(parentFolder);
+ Assert.AreEqual(Path.GetDirectoryName(tempFile), parentFolder.Path.LocalPath);
+
+ string subPath = Path.Combine(Path.GetDirectoryName(tempFile)!, nameof(TestFileSemantics));
+ if (Directory.Exists(subPath))
+ Directory.Delete(subPath);
+
+ IStorageFolder subFolder = await storageProvider.TryGetFolderFromPathAsync(new Uri($"file://{subPath}"));
+ Assert.IsNull(subFolder);
+
+ subFolder = await parentFolder.CreateFolderAsync(nameof(TestFileSemantics));
+ Assert.IsNotNull(subFolder);
+ Assert.IsTrue(new DirectoryInfo(subFolder.Path.LocalPath).Exists);
+
+ IStorageItem newFile = await file.MoveAsync(subFolder);
+ Assert.True(File.Exists(newFile.Path?.LocalPath));
+ Assert.False(File.Exists(tempFile));
+ Assert.AreEqual(
+ new Uri(
+ $"file://{parentFolder.Path.LocalPath}/{nameof(TestFileSemantics)}/{Path.GetFileName(tempFile)}"),
+ newFile.Path);
+ await newFile.DeleteAsync();
+ Assert.False(File.Exists(newFile.Path.LocalPath));
+
+ await subFolder.DeleteAsync();
+ Assert.IsFalse(new DirectoryInfo(subFolder.Path.LocalPath).Exists);
+ }
+
+ [Test]
+ public async Task TestWellKnownFolder()
+ {
+ var storageProvider = new ConsoloniaStorageProvider();
+ IStorageFolder folder = await storageProvider.TryGetWellKnownFolderAsync(WellKnownFolder.Pictures);
+ if (folder != null)
+ Assert.AreEqual(Environment.GetFolderPath(Environment.SpecialFolder.MyPictures), folder.Path.LocalPath);
+
+ folder = await storageProvider.TryGetWellKnownFolderAsync(WellKnownFolder.Documents);
+ if (folder != null)
+ Assert.AreEqual(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),
+ folder.Path.LocalPath);
+
+ folder = await storageProvider.TryGetWellKnownFolderAsync(WellKnownFolder.Music);
+ if (folder != null)
+ Assert.AreEqual(Environment.GetFolderPath(Environment.SpecialFolder.MyMusic), folder.Path.LocalPath);
+
+ folder = await storageProvider.TryGetWellKnownFolderAsync(WellKnownFolder.Videos);
+ if (folder != null)
+ Assert.AreEqual(Environment.GetFolderPath(Environment.SpecialFolder.MyVideos), folder.Path.LocalPath);
+
+ folder = await storageProvider.TryGetWellKnownFolderAsync(WellKnownFolder.Downloads);
+ if (folder != null)
+ Assert.AreEqual(
+ Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "Downloads"),
+ folder.Path.LocalPath);
+
+ folder = await storageProvider.TryGetWellKnownFolderAsync(WellKnownFolder.Desktop);
+ if (folder != null)
+ Assert.AreEqual(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), folder.Path.LocalPath);
+ }
+
+
+ [Test]
+ public async Task TestFolderSemantics()
+ {
+ var storageProvider = new ConsoloniaStorageProvider();
+ string tempPath = Path.GetTempPath();
+ IStorageFolder tempFolder = await storageProvider.TryGetFolderFromPathAsync(new Uri($"file://{tempPath}"));
+ string testPath = Path.Combine(tempPath, nameof(TestFolderSemantics))!;
+ IStorageFolder testFolder = await tempFolder.CreateFolderAsync(nameof(TestFolderSemantics));
+
+ Assert.IsNotNull(testFolder);
+ Assert.AreEqual(testPath, testFolder.Path.LocalPath);
+ Assert.IsFalse(testFolder.CanBookmark);
+ Assert.AreEqual(nameof(TestFolderSemantics), testFolder.Name);
+ IStorageFile file = await testFolder.CreateFileAsync($"{nameof(TestFolderSemantics)}.txt");
+ Assert.IsTrue(File.Exists(file.Path?.LocalPath));
+
+ StorageItemProperties props = await testFolder.GetBasicPropertiesAsync();
+ Assert.AreEqual(Directory.GetCreationTime(testPath).ToString("G", CultureInfo.InvariantCulture),
+ props.DateCreated?.DateTime.ToString("G", CultureInfo.InvariantCulture));
+ Assert.AreEqual(Directory.GetLastWriteTime(testPath).ToString("G", CultureInfo.InvariantCulture),
+ props.DateModified?.DateTime.ToString("G", CultureInfo.InvariantCulture));
+
+ await file.DeleteAsync();
+ Assert.IsFalse(File.Exists(file.Path?.LocalPath));
+
+ IStorageFolder subFolder = await testFolder.CreateFolderAsync("sub");
+ Assert.IsTrue(Directory.Exists(subFolder.Path?.LocalPath));
+
+ file = await subFolder.CreateFileAsync($"{nameof(TestFolderSemantics)}.txt");
+ Assert.IsTrue(File.Exists(file.Path?.LocalPath));
+
+ await foreach (IStorageItem item in subFolder.GetItemsAsync())
+ Assert.AreEqual(file.Path.LocalPath, item.Path.LocalPath);
+ await file.DeleteAsync();
+
+ await subFolder.DeleteAsync();
+ Assert.IsFalse(Directory.Exists(subFolder.Path.LocalPath));
+
+ await testFolder.DeleteAsync();
+ Assert.IsFalse(Directory.Exists(testPath));
+ }
+ }
+}
\ No newline at end of file