Port Camelotia to Windows Presentation Foundation (#28)

* Bootstrap WPF project
* Add MahApps and Material Design controls
* Update README.md
This commit is contained in:
Artyom 2019-08-05 22:57:17 +03:00 коммит произвёл GitHub
Родитель 5ed27086f3
Коммит c73a4b399f
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
31 изменённых файлов: 1562 добавлений и 16 удалений

Просмотреть файл

@ -8,10 +8,10 @@ File manager for cloud storages. Supports Yandex Disk, Google Drive, VK Document
<img src="images/UiAvalonia.png" width="450">
In order to compile .NET Standard libraries, run tests and run an Avalonia application on Windows, Linux and macOS operating systems make sure to have latest [.NET Core SDK](https://dot.net/) installed. Launch the `Camelotia.Avalonia.sln` file to browse or to edit source files. Camelotia uses [Nuke Build](https://github.com/nuke-build/nuke) to build and test the solution. Execute the following commands to run the build scripts on Linux or MacOS:
In order to compile .NET Standard libraries, run tests and run the <a href="http://github.com/avaloniaui">Avalonia</a> application on Windows, Linux or MacOS operating system make sure to have latest [.NET Core SDK](https://dot.net/) installed. Launch the `Camelotia.Avalonia.sln` file to browse or to edit source files. Camelotia uses [Nuke Build](https://github.com/nuke-build/nuke) to build and test the solution. Execute the following commands to run the build scripts on Linux or MacOS:
```sh
# Linux or MacOS shell. Launches Avalonia GUI after build.
# Linux or MacOS shell. Launches the Avalonia app after build.
git clone https://github.com/worldbeater/Camelotia
cd ./Camelotia && bash ./build.sh --interactive
```
@ -19,8 +19,9 @@ cd ./Camelotia && bash ./build.sh --interactive
On Windows, execute the following command line:
```sh
# Windows command line. Launches Avalonia GUI after build.
# Use --full option to compile Android and UWP apps as well.
# Windows command line. Launches the Avalonia app after build.
# Use the '--full' option to compile Android, UWP and WPF apps as well.
# Use the '--configuration Release' option to generate app packages.
git clone https://github.com/worldbeater/Camelotia
cd ./Camelotia && powershell -ExecutionPolicy Unrestricted ./build.ps1 --interactive
```
@ -29,14 +30,20 @@ cd ./Camelotia && powershell -ExecutionPolicy Unrestricted ./build.ps1 --interac
<img src="images/UiWindows.png" width="450">
Universal Windows Platform Camelotia app can be compiled only on latest Windows 10. Make sure to have latest [Microsoft Visual Studio](https://visualstudio.microsoft.com/) installed. Make sure the "Universal Application Development" section is checked in [Visual Studio Installer](https://visualstudio.microsoft.com/ru/vs/). Launch the `Camelotia.Uwp.sln` solution file.
<a href="https://docs.microsoft.com/en-us/windows/uwp/get-started/universal-application-platform-guide">Universal Windows Platform</a> Camelotia app is compatible with Windows 10-based devices, such as PCs, Xbox One and HoloLens. The app can be compiled only on latest Windows 10. Make sure to have latest [Microsoft Visual Studio](https://visualstudio.microsoft.com/) installed. Make sure the "Universal Application Development" section is checked in [Visual Studio Installer](https://visualstudio.microsoft.com/ru/vs/). Launch the `Camelotia.Uwp.sln` solution file.
### Compiling Windows Presentation Foundation app
<img src="images/UiPresentation.png" width="450">
The app was ported to WPF to make the cloud file manager controls reusable across most popular .NET implementations, so one could easily embed parts of Camelotia into their own applications by simply copying and pasting the source files. The app is also compatible with Windows versions lower than 10, such as Windows 7 or 8. To compile the WPF app, ensure the "Desktop Development" section is checked in [Visual Studio Installer](https://visualstudio.microsoft.com/ru/vs/). Then, open the `Camelotia.Wpf.sln` file in Visual Studio 2019.
### Compiling Xamarin Forms app
To compile the Xamarin Forms Android application, install the appropriate Android SDK v8.1. This can be achieved by using [Visual Studio Installer](https://visualstudio.microsoft.com/ru/vs/) and selecting "Mobile Development" section there. Launch the `Camelotia.Xamarin.sln` solution file.
<img src="images/UiAndroid.png" width="450">
To compile the <a href="https://docs.microsoft.com/en-us/xamarin/xamarin-forms/">Xamarin.Forms</a> Android application, install the appropriate Android SDK v8.1. This can be achieved by using [Visual Studio Installer](https://visualstudio.microsoft.com/ru/vs/) and selecting "Mobile Development" section there. Launch the `Camelotia.Xamarin.sln` solution file.
### Technologies and Tools Used
- <a href="https://reactiveui.net/">ReactiveUI</a> modern MVVM framework
@ -52,5 +59,9 @@ To compile the Xamarin Forms Android application, install the appropriate Androi
- <a href="https://github.com/robinrodricks/FluentFTP">FluentFTP</a> FTP implementation
- <a href="https://github.com/sshnet/SSH.NET/">SSH.NET</a> SFTP implementation
- <a href="https://github.com/vknet/vk">VkNet</a> Vkontakte SDK for .NET
- <a href="https://github.com/googleapis/google-api-dotnet-client">Google Drive</a> SDK for .NET
- <a href="https://github.com/googleapis/google-api-dotnet-client">Google Drive</a> client SDK for .NET
- <a href="https://github.com/MaterialDesignInXAML/MaterialDesignInXamlToolkit">Material Design</a> XAML controls and styles
- <a href="https://github.com/MahApps/MahApps.Metro">MahApps Metro</a> XAML controls and styled windows
- <a href="https://reactiveui.net/docs/handbook/events/">ReactiveUI.Events</a> turning regular events into observables
- <a href="https://github.com/Fody/Costura">Costura.Fody</a> which embeds references as resources
- <a href="https://www.jetbrains.com/rider/">JetBrains Rider</a> and <a href="https://visualstudio.microsoft.com/">Microsoft Visual Studio</a> IDEs

Просмотреть файл

@ -81,7 +81,7 @@ internal class Build : NukeBuild
void BuildApp(MSBuildTargetPlatform platform)
{
Logger.Normal($"Cleaning UAP project...");
Logger.Normal("Cleaning UAP project...");
MSBuild(settings => settings
.SetProjectFile(project)
.SetTargets("Clean"));
@ -106,7 +106,7 @@ internal class Build : NukeBuild
.Executes(() =>
{
var execute = EnvironmentInfo.IsWin && Full;
Logger.Normal($"Should compile for Android: {execute}");
Logger.Info($"Should compile for Android: {execute}");
if (!execute) return;
Logger.Normal("Restoring packages required by Xamarin Android...");
@ -116,14 +116,14 @@ internal class Build : NukeBuild
.SetTargets("Restore"));
Logger.Success("Successfully restored Xamarin Android packages.");
Logger.Normal($"Building Xamarin Android project...");
Logger.Normal("Building Xamarin Android project...");
var java = Environment.GetEnvironmentVariable("JAVA_HOME");
MSBuild(settings => settings
.SetProjectFile(project)
.SetTargets("Build")
.SetConfiguration(Configuration)
.SetProperty("JavaSdkDirectory", java));
Logger.Success($"Successfully built Xamarin Android project.");
Logger.Success("Successfully built Xamarin Android project.");
Logger.Normal("Signing Android package...");
MSBuild(settings => settings
@ -131,19 +131,43 @@ internal class Build : NukeBuild
.SetTargets("SignAndroidPackage")
.SetConfiguration(Configuration)
.SetProperty("JavaSdkDirectory", java));
Logger.Success($"Successfully signed Xamarin Android APK.");
Logger.Success("Successfully signed Xamarin Android APK.");
Logger.Normal("Moving APK files to artifacts directory...");
SourceDirectory
.GlobFiles("**/bin/**/*-Signed.apk")
.ForEach(file => MoveFileToDirectory(file, ArtifactsDirectory));
Logger.Success($"Successfully moved APK files.");
Logger.Success("Successfully moved APK files.");
});
Target CompileWindowsPresentationApp => _ => _
.DependsOn(RunUnitTests)
.Executes(() =>
{
var execute = EnvironmentInfo.IsWin && Full;
Logger.Info($"Should compile for WPF: {execute}");
if (!execute) return;
Logger.Normal("Restoring packages required by WPF app...");
var project = SourceDirectory.GlobFiles("**/*.Wpf.csproj").First();
MSBuild(settings => settings
.SetProjectFile(project)
.SetTargets("Restore"));
Logger.Success("Successfully restored Wpf packages.");
Logger.Normal("Building WPF project...");
MSBuild(settings => settings
.SetProjectFile(project)
.SetTargets("Build")
.SetConfiguration(Configuration));
Logger.Success("Successfully built WPF project.");
});
Target RunInteractive => _ => _
.DependsOn(CompileAvaloniaApp)
.DependsOn(CompileUniversalWindowsApp)
.DependsOn(CompileXamarinAndroidApp)
.DependsOn(CompileWindowsPresentationApp)
.Executes(() => SourceDirectory
.GlobFiles($"**/{InteractiveProjectName}.csproj")
.Where(x => Interactive)

Двоичные данные
images/UiPresentation.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 153 KiB

Просмотреть файл

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
</startup>
</configuration>

Просмотреть файл

@ -0,0 +1,45 @@
<Application x:Class="Camelotia.Presentation.Wpf.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:system="clr-namespace:System;assembly=mscorlib"
ShutdownMode="OnExplicitShutdown"
Startup="OnApplicationStartup"
x:Name="CamelotiaApp">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Fonts.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Colors.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/BaseLight.xaml" />
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Light.xaml" />
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Defaults.xaml" />
<ResourceDictionary Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Primary/MaterialDesignColor.Indigo.xaml" />
<ResourceDictionary Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Accent/MaterialDesignColor.Yellow.xaml" />
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.MahApps;component/Themes/MaterialDesignTheme.MahApps.Fonts.xaml" />
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.MahApps;component/Themes/MaterialDesignTheme.MahApps.Flyout.xaml" />
</ResourceDictionary.MergedDictionaries>
<system:Double x:Key="WindowTitleFontSize">12</system:Double>
<BooleanToVisibilityConverter x:Key="BooleanToVisibility" />
<SolidColorBrush x:Key="HighlightBrush" Color="{DynamicResource Primary700}"/>
<SolidColorBrush x:Key="AccentBaseColorBrush" Color="{DynamicResource Primary600}" />
<SolidColorBrush x:Key="AccentColorBrush" Color="{DynamicResource Primary500}"/>
<SolidColorBrush x:Key="AccentColorBrush2" Color="{DynamicResource Primary400}"/>
<SolidColorBrush x:Key="AccentColorBrush3" Color="{DynamicResource Primary300}"/>
<SolidColorBrush x:Key="AccentColorBrush4" Color="{DynamicResource Primary200}"/>
<SolidColorBrush x:Key="WindowTitleColorBrush" Color="{DynamicResource Primary700}"/>
<SolidColorBrush x:Key="AccentSelectedColorBrush" Color="{DynamicResource Primary500Foreground}"/>
<LinearGradientBrush x:Key="ProgressBrush" EndPoint="0.001,0.5" StartPoint="1.002,0.5">
<GradientStop Color="{DynamicResource Primary700}" Offset="0"/>
<GradientStop Color="{DynamicResource Primary300}" Offset="1"/>
</LinearGradientBrush>
<SolidColorBrush x:Key="CheckmarkFill" Color="{DynamicResource Primary500}"/>
<SolidColorBrush x:Key="RightArrowFill" Color="{DynamicResource Primary500}"/>
<SolidColorBrush x:Key="IdealForegroundColorBrush" Color="{DynamicResource Primary500Foreground}"/>
<SolidColorBrush x:Key="IdealForegroundDisabledBrush" Color="{DynamicResource Primary500}" Opacity="0.4"/>
<SolidColorBrush x:Key="MahApps.Metro.Brushes.ToggleSwitchButton.OnSwitchBrush.Win10" Color="{DynamicResource Primary500}" />
<SolidColorBrush x:Key="MahApps.Metro.Brushes.ToggleSwitchButton.OnSwitchMouseOverBrush.Win10" Color="{DynamicResource Primary400}" />
<SolidColorBrush x:Key="MahApps.Metro.Brushes.ToggleSwitchButton.ThumbIndicatorCheckedBrush.Win10" Color="{DynamicResource Primary500Foreground}" />
</ResourceDictionary>
</Application.Resources>
</Application>

Просмотреть файл

@ -0,0 +1,63 @@
using Camelotia.Presentation.ViewModels;
using Camelotia.Presentation.Wpf.Services;
using Camelotia.Services.Interfaces;
using Camelotia.Services.Models;
using Camelotia.Services.Providers;
using Camelotia.Services.Storages;
using ReactiveUI;
using System;
using System.Collections.Generic;
using System.Reactive.Concurrency;
using System.Windows;
namespace Camelotia.Presentation.Wpf
{
public partial class App : Application
{
public App() => InitializeComponent();
private void OnApplicationStartup(object sender, StartupEventArgs e)
{
var current = CurrentThreadScheduler.Instance;
var main = RxApp.MainThreadScheduler;
Akavache.BlobCache.ApplicationName = "Camelotia";
var cache = Akavache.BlobCache.UserAccount;
var login = new WindowsPresentationYandexAuthenticator();
var files = new WindowsPresentationFileManager();
var mainViewModel = new MainViewModel(
(provider, auth) => new ProviderViewModel(
model => new CreateFolderViewModel(model, provider, current, main),
model => new RenameFileViewModel(model, provider, current, main),
(file, model) => new FileViewModel(model, file),
auth, files, provider, current, main
),
provider => new AuthViewModel(
new DirectAuthViewModel(provider, current, main),
new HostAuthViewModel(provider, current, main),
new OAuthViewModel(provider, current, main),
provider, current, main
),
new ProviderStorage(
new Dictionary<string, Func<ProviderModel, IProvider>>
{
["Local Storage"] = id => new LocalProvider(id),
["Yandex Disk"] = id => new YandexDiskProvider(id, login, cache),
["Vkontakte Docs"] = id => new VkDocsProvider(id, cache),
["Google Drive"] = id => new GoogleDriveProvider(id, cache),
["FTP"] = id => new FtpProvider(id),
["SFTP"] = id => new SftpProvider(id),
["GitHub"] = id => new GitHubProvider(id, cache)
},
cache
),
current, main
);
var window = new MainView { DataContext = mainViewModel };
window.Closed += delegate { Shutdown(); };
window.Show();
}
}
}

Просмотреть файл

@ -0,0 +1,183 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{E9EEEBF4-5F8D-480C-BD0A-9E5801189424}</ProjectGuid>
<OutputType>WinExe</OutputType>
<RootNamespace>Camelotia.Presentation.Wpf</RootNamespace>
<AssemblyName>Camelotia.Presentation.Wpf</AssemblyName>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<WarningLevel>4</WarningLevel>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<Deterministic>true</Deterministic>
<StartupObject>Camelotia.Presentation.Wpf.Program</StartupObject>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Drawing" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xaml">
<RequiredTargetFramework>4.0</RequiredTargetFramework>
</Reference>
<Reference Include="WindowsBase" />
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
</ItemGroup>
<ItemGroup>
<ApplicationDefinition Include="App.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</ApplicationDefinition>
<Compile Include="Program.cs" />
<Compile Include="Views\AuthView.xaml.cs">
<DependentUpon>AuthView.xaml</DependentUpon>
</Compile>
<Compile Include="Views\CreateFolderView.xaml.cs">
<DependentUpon>CreateFolderView.xaml</DependentUpon>
</Compile>
<Compile Include="Views\DirectAuthView.xaml.cs">
<DependentUpon>DirectAuthView.xaml</DependentUpon>
</Compile>
<Compile Include="Views\FileView.xaml.cs">
<DependentUpon>FileView.xaml</DependentUpon>
</Compile>
<Compile Include="Views\HostAuthView.xaml.cs">
<DependentUpon>HostAuthView.xaml</DependentUpon>
</Compile>
<Compile Include="Views\OAuthView.xaml.cs">
<DependentUpon>OAuthView.xaml</DependentUpon>
</Compile>
<Compile Include="Views\ProviderView.xaml.cs">
<DependentUpon>ProviderView.xaml</DependentUpon>
</Compile>
<Compile Include="Views\RenameFileView.xaml.cs">
<DependentUpon>RenameFileView.xaml</DependentUpon>
</Compile>
<Page Include="Views\AuthView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\CreateFolderView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\DirectAuthView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\FileView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\HostAuthView.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Views\MainView.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Compile Include="App.xaml.cs">
<DependentUpon>App.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Include="Services\WindowsPresentationYandexAuthenticator.cs" />
<Compile Include="Services\WindowsPresentationFileManager.cs" />
<Compile Include="Views\MainView.xaml.cs">
<DependentUpon>MainView.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Page Include="Views\OAuthView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\ProviderView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\RenameFileView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
<ItemGroup>
<PackageReference Include="akavache">
<Version>6.5.20</Version>
</PackageReference>
<PackageReference Include="Costura.Fody">
<Version>4.0.0</Version>
</PackageReference>
<PackageReference Include="MahApps.Metro">
<Version>1.6.5</Version>
</PackageReference>
<PackageReference Include="MaterialDesignColors">
<Version>1.2.0</Version>
</PackageReference>
<PackageReference Include="MaterialDesignThemes">
<Version>2.6.0</Version>
</PackageReference>
<PackageReference Include="MaterialDesignThemes.MahApps">
<Version>0.1.0</Version>
</PackageReference>
<PackageReference Include="ReactiveUI.Events.WPF">
<Version>9.19.5</Version>
</PackageReference>
<PackageReference Include="ReactiveUI.WPF">
<Version>9.19.5</Version>
</PackageReference>
<PackageReference Include="SQLitePCLRaw.bundle_e_sqlite3">
<Version>1.1.14</Version>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Camelotia.Presentation\Camelotia.Presentation.csproj">
<Project>{777fbfa6-ecfa-42f5-ac5f-efc4b2d4ae6b}</Project>
<Name>Camelotia.Presentation</Name>
</ProjectReference>
<ProjectReference Include="..\Camelotia.Services\Camelotia.Services.csproj">
<Project>{283B8F56-AB9F-4556-AB93-AAC54171841C}</Project>
<Name>Camelotia.Services</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Resource Include="FodyWeavers.xml" />
</ItemGroup>
<!--
Uncomment to have native libraries embedded.
<ItemGroup>
<EmbeddedResource Include="costura32\e_sqlite3.dll" />
<EmbeddedResource Include="costura64\e_sqlite3.dll" />
</ItemGroup>
-->
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

Просмотреть файл

@ -0,0 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<Costura />
</Weavers>

Просмотреть файл

@ -0,0 +1,10 @@
using System;
namespace Camelotia.Presentation.Wpf
{
public sealed class Program
{
[STAThread]
public static void Main(string[] args) => new App().Run();
}
}

Просмотреть файл

@ -0,0 +1,38 @@
using Camelotia.Services.Interfaces;
using System;
using System.IO;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Camelotia.Presentation.Wpf.Services
{
public sealed class WindowsPresentationFileManager : IFileManager
{
public Task<(string Name, Stream Stream)> OpenRead()
{
var dialog = new OpenFileDialog();
if (dialog.ShowDialog() != DialogResult.OK)
throw new Exception("Nothing selected.");
var path = dialog.FileName;
var name = Path.GetFileName(path);
Stream stream = File.OpenRead(path);
return Task.FromResult((name, stream));
}
public Task<Stream> OpenWrite(string name)
{
using (var dialog = new FolderBrowserDialog())
{
var result = dialog.ShowDialog();
if (result != DialogResult.OK)
throw new Exception("Nothing selected.");
var directory = dialog.SelectedPath;
var file = Path.Combine(directory, name);
Stream stream = File.Create(file);
return Task.FromResult(stream);
}
}
}
}

Просмотреть файл

@ -0,0 +1,46 @@
using Camelotia.Services.Interfaces;
using System;
using System.Diagnostics;
using System.Net;
using System.Text;
using System.Threading.Tasks;
namespace Camelotia.Presentation.Wpf.Services
{
public sealed class WindowsPresentationYandexAuthenticator : IAuthenticator
{
private const string SuccessContent = "<html><body>Please return to the app.</body></html>";
public GrantType GrantType => GrantType.AuthorizationCode;
public Task<string> ReceiveToken(Uri uri) => throw new PlatformNotSupportedException();
public async Task<string> ReceiveCode(Uri uri, Uri returnUri)
{
var server = returnUri.ToString();
var listener = new HttpListener();
listener.Prefixes.Add(server);
listener.Start();
new Process
{
StartInfo = new ProcessStartInfo
{
UseShellExecute = true,
FileName = uri.ToString()
}
}
.Start();
var context = await listener.GetContextAsync();
var code = context.Request.QueryString["code"];
var buffer = Encoding.UTF8.GetBytes(SuccessContent);
context.Response.ContentLength64 = buffer.Length;
await context.Response.OutputStream.WriteAsync(buffer, 0, buffer.Length);
context.Response.Close();
listener.Close();
return code;
}
}
}

Просмотреть файл

@ -0,0 +1,31 @@
<UserControl
x:Class="Camelotia.Presentation.Wpf.Views.AuthView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Camelotia.Presentation.Wpf.Views"
d:DesignHeight="450"
d:DesignWidth="800"
mc:Ignorable="d">
<TabControl x:Name="AuthTabs">
<TabItem>
<TabItem.Header>
<TextBlock FontSize="15" Margin="5" Text="Direct Auth" Visibility="{Binding SupportsDirectAuth, Converter={StaticResource BooleanToVisibility}}" />
</TabItem.Header>
<local:DirectAuthView DataContext="{Binding DirectAuth}" />
</TabItem>
<TabItem>
<TabItem.Header>
<TextBlock FontSize="15" Margin="5" Text="Host Auth" Visibility="{Binding SupportsHostAuth, Converter={StaticResource BooleanToVisibility}}" />
</TabItem.Header>
<local:HostAuthView DataContext="{Binding HostAuth}" />
</TabItem>
<TabItem>
<TabItem.Header>
<TextBlock FontSize="15" Margin="5" Text="Open Auth" Visibility="{Binding SupportsOAuth, Converter={StaticResource BooleanToVisibility}}" />
</TabItem.Header>
<local:OAuthView DataContext="{Binding OAuth}" />
</TabItem>
</TabControl>
</UserControl>

Просмотреть файл

@ -0,0 +1,51 @@
using Camelotia.Presentation.Interfaces;
using ReactiveUI;
using System;
using System.Reactive.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Reactive.Disposables;
namespace Camelotia.Presentation.Wpf.Views
{
public partial class AuthView : UserControl, IViewFor<IAuthViewModel>
{
public static readonly DependencyProperty ViewModelProperty = DependencyProperty
.Register(nameof(ViewModel), typeof(IAuthViewModel), typeof(AuthView), null);
public AuthView()
{
InitializeComponent();
DataContextChanged += (sender, args) => ViewModel = DataContext as IAuthViewModel;
this.WhenActivated(disposable =>
{
this.WhenAnyValue(x => x.ViewModel.SupportsDirectAuth)
.Where(supports => supports)
.Subscribe(supports => AuthTabs.SelectedIndex = 0)
.DisposeWith(disposable);
this.WhenAnyValue(x => x.ViewModel.SupportsHostAuth)
.Where(supports => supports)
.Subscribe(supports => AuthTabs.SelectedIndex = 1)
.DisposeWith(disposable);
this.WhenAnyValue(x => x.ViewModel.SupportsOAuth)
.Where(supports => supports)
.Subscribe(supports => AuthTabs.SelectedIndex = 2)
.DisposeWith(disposable);
});
}
public IAuthViewModel ViewModel
{
get => (IAuthViewModel)GetValue(ViewModelProperty);
set => SetValue(ViewModelProperty, value);
}
object IViewFor.ViewModel
{
get => ViewModel;
set => ViewModel = (IAuthViewModel)value;
}
}
}

Просмотреть файл

@ -0,0 +1,55 @@
<UserControl
x:Class="Camelotia.Presentation.Wpf.Views.CreateFolderView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
d:DesignHeight="450"
d:DesignWidth="800"
mc:Ignorable="d">
<StackPanel VerticalAlignment="Center"
HorizontalAlignment="Center"
Width="300">
<TextBlock Text="Create Folder"
Foreground="#002171"
FontSize="16"
Margin="0 10" />
<ProgressBar HorizontalAlignment="Stretch"
IsIndeterminate="{Binding IsLoading}"
Visibility="{Binding IsLoading, Converter={StaticResource BooleanToVisibility}}"
Margin="0 5" />
<StackPanel Visibility="{Binding HasErrors, Converter={StaticResource BooleanToVisibility}}"
Background="#ffeeee"
Margin="0 5">
<StackPanel Margin="10">
<TextBlock Text="{Binding ErrorMessage}"
Foreground="#990000"
TextWrapping="Wrap" />
</StackPanel>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="0 5">
<TextBlock Text="Creating new folder at:" Margin="0 0 5 0" />
<TextBlock Text="{Binding Path}" Foreground="#002171" />
</StackPanel>
<TextBlock Text="Please, enter new folder name:" Margin="0 5" />
<TextBox Text="{Binding Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
materialDesign:HintAssist.Hint="Folder name" />
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="3*" />
<ColumnDefinition Width="2*" />
</Grid.ColumnDefinitions>
<Button Grid.Column="0"
Content="Create folder"
HorizontalAlignment="Stretch"
Command="{Binding Create}"
Margin="0 10 10 10" />
<Button Grid.Column="1"
Content="Close"
HorizontalAlignment="Stretch"
Command="{Binding Close}"
Margin="0 10" />
</Grid>
</StackPanel>
</UserControl>

Просмотреть файл

@ -0,0 +1,32 @@
using Camelotia.Presentation.Interfaces;
using ReactiveUI;
using System.Windows;
using System.Windows.Controls;
namespace Camelotia.Presentation.Wpf.Views
{
public partial class CreateFolderView : UserControl, IViewFor<ICreateFolderViewModel>
{
public static readonly DependencyProperty ViewModelProperty = DependencyProperty
.Register(nameof(ViewModel), typeof(ICreateFolderViewModel), typeof(CreateFolderView), null);
public CreateFolderView()
{
InitializeComponent();
DataContextChanged += (sender, args) => ViewModel = DataContext as ICreateFolderViewModel;
this.WhenActivated(disposable => { });
}
public ICreateFolderViewModel ViewModel
{
get => (ICreateFolderViewModel)GetValue(ViewModelProperty);
set => SetValue(ViewModelProperty, value);
}
object IViewFor.ViewModel
{
get => ViewModel;
set => ViewModel = (ICreateFolderViewModel)value;
}
}
}

Просмотреть файл

@ -0,0 +1,39 @@
<UserControl
x:Class="Camelotia.Presentation.Wpf.Views.DirectAuthView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
d:DesignHeight="300"
d:DesignWidth="300"
mc:Ignorable="d">
<materialDesign:Card Width="300" VerticalAlignment="Center">
<StackPanel VerticalAlignment="Center"
HorizontalAlignment="Stretch"
Margin="20">
<ProgressBar HorizontalAlignment="Stretch"
IsIndeterminate="{Binding IsBusy}"
Visibility="{Binding IsBusy, Converter={StaticResource BooleanToVisibility}}"
Margin="0 5" />
<StackPanel Visibility="{Binding HasErrors, Converter={StaticResource BooleanToVisibility}}"
Background="{StaticResource PrimaryHueDarkBrush}"
Margin="0 5">
<StackPanel Margin="10">
<TextBlock Text="{Binding ErrorMessage}"
Foreground="White"
TextWrapping="Wrap" />
</StackPanel>
</StackPanel>
<TextBox Text="{Binding Username, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
materialDesign:HintAssist.Hint="User name"
Margin="0 15 0 10" />
<TextBox Text="{Binding Password, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
materialDesign:HintAssist.Hint="Password"
Margin="0 5 0 15" />
<Button Content="Login"
HorizontalAlignment="Stretch"
Command="{Binding Login}" />
</StackPanel>
</materialDesign:Card>
</UserControl>

Просмотреть файл

@ -0,0 +1,32 @@
using Camelotia.Presentation.Interfaces;
using ReactiveUI;
using System.Windows;
using System.Windows.Controls;
namespace Camelotia.Presentation.Wpf.Views
{
public partial class DirectAuthView : UserControl, IViewFor<IDirectAuthViewModel>
{
public static readonly DependencyProperty ViewModelProperty = DependencyProperty
.Register(nameof(ViewModel), typeof(IDirectAuthViewModel), typeof(DirectAuthView), null);
public DirectAuthView()
{
InitializeComponent();
DataContextChanged += (sender, args) => ViewModel = DataContext as IDirectAuthViewModel;
this.WhenActivated(disposable => { });
}
public IDirectAuthViewModel ViewModel
{
get => (IDirectAuthViewModel)GetValue(ViewModelProperty);
set => SetValue(ViewModelProperty, value);
}
object IViewFor.ViewModel
{
get => ViewModel;
set => ViewModel = (IDirectAuthViewModel)value;
}
}
}

Просмотреть файл

@ -0,0 +1,57 @@
<UserControl
x:Class="Camelotia.Presentation.Wpf.Views.FileView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
d:DesignHeight="450"
d:DesignWidth="800"
mc:Ignorable="d">
<Grid Margin="6">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="3*" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="2*" />
</Grid.ColumnDefinitions>
<materialDesign:PackIcon
Grid.Column="0"
Kind="Folder"
VerticalAlignment="Center"
HorizontalAlignment="Center"
Foreground="{StaticResource PrimaryHueDarkBrush}"
Visibility="{Binding IsFolder, Converter={StaticResource BooleanToVisibility}}"
Margin="0 0 5 0"
Height="16"
Width="16" />
<materialDesign:PackIcon
Grid.Column="0"
Kind="File"
VerticalAlignment="Center"
HorizontalAlignment="Center"
Foreground="{StaticResource SecondaryAccentBrush}"
Visibility="{Binding IsFile, Converter={StaticResource BooleanToVisibility}}"
Margin="0 0 5 0"
Height="16"
Width="16" />
<TextBlock Grid.Column="1"
Text="{Binding Name}"
TextWrapping="Wrap"
FontSize="14" />
<TextBlock Grid.Column="2"
Text="Directory"
Visibility="{Binding IsFolder, Converter={StaticResource BooleanToVisibility}}"
Foreground="#777777"
FontSize="12" />
<TextBlock Grid.Column="3"
VerticalAlignment="Center"
Foreground="#777777"
Text="{Binding Size}" />
<TextBlock Grid.Column="4"
VerticalAlignment="Center"
Foreground="#777777"
Text="{Binding Modified}" />
</Grid>
</UserControl>

Просмотреть файл

@ -0,0 +1,42 @@
using Camelotia.Presentation.Interfaces;
using ReactiveUI;
using System.Reactive;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Windows;
using System.Windows.Controls;
namespace Camelotia.Presentation.Wpf.Views
{
public partial class FileView : UserControl, IViewFor<IFileViewModel>
{
public static readonly DependencyProperty ViewModelProperty = DependencyProperty
.Register(nameof(ViewModel), typeof(IFileViewModel), typeof(FileView), null);
public FileView()
{
InitializeComponent();
DataContextChanged += (sender, args) => ViewModel = DataContext as IFileViewModel;
this.WhenActivated(disposable =>
{
this.Events()
.MouseDoubleClick
.Select(args => Unit.Default)
.InvokeCommand(ViewModel.Provider.Open)
.DisposeWith(disposable);
});
}
public IFileViewModel ViewModel
{
get => (IFileViewModel)GetValue(ViewModelProperty);
set => SetValue(ViewModelProperty, value);
}
object IViewFor.ViewModel
{
get => ViewModel;
set => ViewModel = (IFileViewModel)value;
}
}
}

Просмотреть файл

@ -0,0 +1,51 @@
<UserControl
x:Class="Camelotia.Presentation.Wpf.Views.HostAuthView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
d:DesignHeight="300"
d:DesignWidth="300"
mc:Ignorable="d" >
<materialDesign:Card Width="300" VerticalAlignment="Center">
<StackPanel VerticalAlignment="Center"
HorizontalAlignment="Stretch"
Margin="20">
<ProgressBar HorizontalAlignment="Stretch"
IsIndeterminate="{Binding IsBusy}"
Visibility="{Binding IsBusy, Converter={StaticResource BooleanToVisibility}}"
Margin="0 5" />
<StackPanel Visibility="{Binding HasErrors, Converter={StaticResource BooleanToVisibility}}"
Background="{StaticResource PrimaryHueDarkBrush}"
Margin="0 5">
<StackPanel Margin="10">
<TextBlock Text="{Binding ErrorMessage}"
Foreground="White"
TextWrapping="Wrap" />
</StackPanel>
</StackPanel>
<Grid Margin="0 15 0 5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="3*" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<TextBox Grid.Column="0"
materialDesign:HintAssist.Hint="Host address"
Text="{Binding Address, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
<TextBox Grid.Column="1" Margin="5 0 0 0"
materialDesign:HintAssist.Hint="Port"
Text="{Binding Port, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
</Grid>
<TextBox Text="{Binding Username, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
materialDesign:HintAssist.Hint="User name"
Margin="0 10" />
<TextBox Text="{Binding Password, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
materialDesign:HintAssist.Hint="Password"
Margin="0 5 0 15" />
<Button Content="Login"
HorizontalAlignment="Stretch"
Command="{Binding Login}" />
</StackPanel>
</materialDesign:Card>
</UserControl>

Просмотреть файл

@ -0,0 +1,32 @@
using Camelotia.Presentation.Interfaces;
using ReactiveUI;
using System.Windows;
using System.Windows.Controls;
namespace Camelotia.Presentation.Wpf.Views
{
public partial class HostAuthView : UserControl, IViewFor<IHostAuthViewModel>
{
public static readonly DependencyProperty ViewModelProperty = DependencyProperty
.Register(nameof(ViewModel), typeof(IHostAuthViewModel), typeof(HostAuthView), null);
public HostAuthView()
{
InitializeComponent();
DataContextChanged += (sender, args) => ViewModel = DataContext as IHostAuthViewModel;
this.WhenActivated(disposable => { });
}
public IHostAuthViewModel ViewModel
{
get => (IHostAuthViewModel)GetValue(ViewModelProperty);
set => SetValue(ViewModelProperty, value);
}
object IViewFor.ViewModel
{
get => ViewModel;
set => ViewModel = (IHostAuthViewModel)value;
}
}
}

Просмотреть файл

@ -0,0 +1,140 @@
<mah:MetroWindow
xmlns:mah="http://metro.mahapps.com/winfx/xaml/controls"
x:Class="Camelotia.Presentation.Wpf.MainView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:views="clr-namespace:Camelotia.Presentation.Wpf.Views"
TextElement.Foreground="{DynamicResource MaterialDesignBody}"
TextElement.FontWeight="Regular"
TextElement.FontSize="13"
TextOptions.TextFormattingMode="Ideal"
TextOptions.TextRenderingMode="Auto"
Background="{DynamicResource MaterialDesignPaper}"
FontFamily="{DynamicResource MaterialDesignFont}"
WindowTitleBrush="{DynamicResource PrimaryHueDarkBrush}"
NonActiveWindowTitleBrush="{DynamicResource PrimaryHueDarkBrush}"
WindowStartupLocation="CenterScreen"
SaveWindowPosition="False"
ResizeBorderThickness="5"
BorderThickness="0"
GlowBrush="Black"
Title="Camelotia"
mc:Ignorable="d"
Height="500"
Width="800">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="2*" />
</Grid.ColumnDefinitions>
<Grid Grid.Column="0">
<Grid.RowDefinitions>
<RowDefinition Height="40" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid Grid.Row="0" Background="{StaticResource PrimaryHueDarkBrush}">
<TextBlock VerticalAlignment="Center"
Text="Connected Storages"
Foreground="#ffffff"
FontSize="17"
Margin="10" />
</Grid>
<Border BorderBrush="#eeeeee"
BorderThickness="0 0 2 0"
Grid.Row="1">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<ComboBox Margin="10"
Grid.Column="0"
ItemsSource="{Binding SupportedTypes, Mode=OneWay}"
SelectedItem="{Binding SelectedSupportedType, Mode=TwoWay}" />
<Button Command="{Binding Add}"
Grid.Column="1"
Content="Add"
Margin="10" />
</Grid>
</Border>
<ListBox Grid.Row="2"
BorderBrush="#eeeeee"
BorderThickness="0 2 2 0"
SelectedItem="{Binding SelectedProvider, Mode=TwoWay}"
ItemsSource="{Binding Providers, Mode=OneWay}">
<ListBox.ItemTemplate>
<DataTemplate>
<materialDesign:TransitioningContent>
<materialDesign:TransitioningContent.OpeningEffects>
<materialDesign:TransitionEffect Kind="SlideInFromRight" />
</materialDesign:TransitioningContent.OpeningEffects>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="70" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<materialDesign:PackIcon
Grid.Column="0"
Kind="CloudCircle"
VerticalAlignment="Center"
HorizontalAlignment="Center"
Foreground="{StaticResource PrimaryHueDarkBrush}"
Height="60"
Width="60" />
<StackPanel Grid.Column="1" Margin="5">
<TextBlock FontSize="15"
Text="{Binding Name}"
Foreground="{StaticResource PrimaryHueDarkBrush}" />
<TextBlock Foreground="{StaticResource PrimaryHueLightForegroundBrush}" Margin="0 5">
<Run Text="Size: " />
<Run Text="{Binding Size, Mode=OneWay}" />
</TextBlock>
<TextBlock Foreground="{StaticResource MaterialDesignTextBoxBorder}"
Text="{Binding Description}"
TextWrapping="Wrap" />
</StackPanel>
</Grid>
</materialDesign:TransitioningContent>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Border BorderBrush="#eeeeee"
BorderThickness="0 2 2 0"
Grid.Row="3">
<Grid Grid.Row="3">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button Grid.Column="0"
Command="{Binding Refresh}"
Content="Refresh"
Margin="10" />
<Button Grid.Column="1"
Command="{Binding Remove}"
Content="Remove"
Margin="10" />
</Grid>
</Border>
</Grid>
<Grid Grid.Column="1">
<views:ProviderView DataContext="{Binding SelectedProvider, Mode=OneWay}" />
<Grid Background="#FFFFFF" Visibility="{Binding WelcomeScreenVisible, Converter={StaticResource BooleanToVisibility}}">
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<materialDesign:PackIcon Kind="CloudOutline"
HorizontalAlignment="Center"
Foreground="{StaticResource PrimaryHueDarkBrush}"
Height="90" Width="90" />
<TextBlock Text="Select existing provider or add a new one!"
Foreground="{StaticResource MaterialDesignTextBoxBorder}"
Margin="10" />
</StackPanel>
</Grid>
</Grid>
</Grid>
</mah:MetroWindow>

Просмотреть файл

@ -0,0 +1,32 @@
using Camelotia.Presentation.Interfaces;
using MahApps.Metro.Controls;
using ReactiveUI;
using System.Windows;
namespace Camelotia.Presentation.Wpf
{
public partial class MainView : MetroWindow, IViewFor<IMainViewModel>
{
public static readonly DependencyProperty ViewModelProperty = DependencyProperty
.Register(nameof(ViewModel), typeof(IMainViewModel), typeof(MainView), null);
public MainView()
{
InitializeComponent();
DataContextChanged += (sender, args) => ViewModel = DataContext as IMainViewModel;
this.WhenActivated(disposable => { });
}
public IMainViewModel ViewModel
{
get => (IMainViewModel)GetValue(ViewModelProperty);
set => SetValue(ViewModelProperty, value);
}
object IViewFor.ViewModel
{
get => ViewModel;
set => ViewModel = (IMainViewModel)value;
}
}
}

Просмотреть файл

@ -0,0 +1,35 @@
<UserControl
x:Class="Camelotia.Presentation.Wpf.Views.OAuthView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
d:DesignHeight="450"
d:DesignWidth="800"
mc:Ignorable="d">
<StackPanel VerticalAlignment="Center"
HorizontalAlignment="Center"
Width="300">
<TextBlock Text="OAuth"
Foreground="#002171"
FontSize="16"
Margin="0 10" />
<ProgressBar HorizontalAlignment="Stretch"
IsIndeterminate="{Binding IsBusy}"
Visibility="{Binding IsBusy, Converter={StaticResource BooleanToVisibility}}"
Margin="0 5" />
<StackPanel Visibility="{Binding HasErrors, Converter={StaticResource BooleanToVisibility}}"
Background="#ffeeee"
Margin="0 5">
<StackPanel Margin="10">
<TextBlock Text="{Binding ErrorMessage}"
TextWrapping="Wrap"
Foreground="#990000" />
</StackPanel>
</StackPanel>
<Button Content="Login"
HorizontalAlignment="Stretch"
Command="{Binding Login}"
Margin="0 10" />
</StackPanel>
</UserControl>

Просмотреть файл

@ -0,0 +1,32 @@
using Camelotia.Presentation.Interfaces;
using ReactiveUI;
using System.Windows;
using System.Windows.Controls;
namespace Camelotia.Presentation.Wpf.Views
{
public partial class OAuthView : UserControl, IViewFor<IOAuthViewModel>
{
public static readonly DependencyProperty ViewModelProperty = DependencyProperty
.Register(nameof(ViewModel), typeof(IOAuthViewModel), typeof(OAuthView), null);
public OAuthView()
{
InitializeComponent();
DataContextChanged += (sender, args) => ViewModel = DataContext as IOAuthViewModel;
this.WhenActivated(disposable => { });
}
public IOAuthViewModel ViewModel
{
get => (IOAuthViewModel)GetValue(ViewModelProperty);
set => SetValue(ViewModelProperty, value);
}
object IViewFor.ViewModel
{
get => ViewModel;
set => ViewModel = (IOAuthViewModel)value;
}
}
}

Просмотреть файл

@ -0,0 +1,200 @@
<UserControl
x:Class="Camelotia.Presentation.Wpf.Views.ProviderView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:views="clr-namespace:Camelotia.Presentation.Wpf.Views"
d:DesignHeight="200"
d:DesignWidth="450"
mc:Ignorable="d">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="40" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid Grid.Row="0" Background="{StaticResource PrimaryHueDarkBrush}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="3*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Button Grid.Column="0"
Command="{Binding Back}"
HorizontalAlignment="Stretch"
Content="{materialDesign:PackIcon Kind=ChevronLeftCircleOutline}"
Style="{StaticResource MaterialDesignToolButton}"
Foreground="White"
Margin="10 0" />
<TextBlock Grid.Column="1"
Text="{Binding CurrentPath}"
VerticalAlignment="Center"
Foreground="White"
Margin="10 0" />
<Button Grid.Column="2"
Command="{Binding Open}"
HorizontalAlignment="Stretch"
Content="{materialDesign:PackIcon Kind=ChevronRightCircleOutline}"
Style="{StaticResource MaterialDesignToolButton}"
Foreground="White"
Margin="10 0" />
</Grid>
<Grid Grid.Row="1" Background="#ffffff">
<ListBox ItemsSource="{Binding Files}"
ScrollViewer.HorizontalScrollBarVisibility="Hidden"
SelectedItem="{Binding SelectedFile, Mode=TwoWay}">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem" BasedOn="{StaticResource MaterialDesignListBoxItem}">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="Padding" Value="8 2" />
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<views:FileView DataContext="{Binding}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Grid Visibility="{Binding HasErrors, Converter={StaticResource BooleanToVisibility}}"
Background="{StaticResource MaterialDesignPaper}">
<StackPanel VerticalAlignment="Center">
<materialDesign:PackIcon Kind="CloudAlert"
HorizontalAlignment="Center"
Foreground="{StaticResource PrimaryHueDarkBrush}"
Height="90"
Width="90" />
<TextBlock Text="Can't perform the operation, an error has occured."
Foreground="{StaticResource MaterialDesignTextBoxBorder}"
HorizontalAlignment="Center"
Margin="10" />
</StackPanel>
</Grid>
<Grid Visibility="{Binding IsCurrentPathEmpty, Converter={StaticResource BooleanToVisibility}}"
Background="{StaticResource MaterialDesignPaper}">
<StackPanel VerticalAlignment="Center">
<materialDesign:PackIcon Kind="TrashEmpty"
HorizontalAlignment="Center"
Foreground="{StaticResource PrimaryHueDarkBrush}"
Height="90"
Width="90" />
<TextBlock Text="Whoops, no files here!"
Foreground="{StaticResource MaterialDesignTextBoxBorder}"
HorizontalAlignment="Center"
Margin="10" />
</StackPanel>
</Grid>
<Grid Visibility="{Binding IsLoading, Converter={StaticResource BooleanToVisibility}}"
Background="{StaticResource MaterialDesignPaper}">
<StackPanel VerticalAlignment="Center">
<ProgressBar HorizontalAlignment="Stretch"
IsIndeterminate="{Binding IsLoading}" />
<TextBlock Text="Please, wait..."
HorizontalAlignment="Center" />
</StackPanel>
</Grid>
<Grid Visibility="{Binding Folder.IsVisible, Converter={StaticResource BooleanToVisibility}}" Background="#fff">
<views:CreateFolderView DataContext="{Binding Folder}" />
</Grid>
<Grid Visibility="{Binding Rename.IsVisible, Converter={StaticResource BooleanToVisibility}}" Background="#fff">
<views:RenameFileView DataContext="{Binding Rename}" />
</Grid>
</Grid>
<Border Grid.Row="2"
BorderBrush="#eeeeee"
BorderThickness="0 2 0 0">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="2*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button Grid.Column="0"
Content="Delete"
HorizontalAlignment="Stretch"
Command="{Binding DeleteSelectedFile}"
Style="{StaticResource MaterialDesignFlatButton}"
Padding="0"
Margin="5" />
<Button Grid.Column="1"
Content="Rename"
HorizontalAlignment="Stretch"
Command="{Binding Rename.Open}"
Style="{StaticResource MaterialDesignFlatButton}"
Padding="0"
Margin="5" />
<StackPanel Grid.Column="2"
VerticalAlignment="Center"
Orientation="Horizontal"
Margin="5">
<TextBlock Text="{Binding SelectedFile.Name}" Foreground="#888888" />
</StackPanel>
<Button Grid.Column="3"
Content="Upload"
HorizontalAlignment="Stretch"
Command="{Binding UploadToCurrentPath}"
Style="{StaticResource MaterialDesignFlatButton}"
Padding="0"
Margin="5" />
<Button Grid.Column="4"
Content="Download"
HorizontalAlignment="Stretch"
Command="{Binding DownloadSelectedFile}"
Style="{StaticResource MaterialDesignFlatButton}"
Padding="0"
Margin="5" />
</Grid>
</Border>
<Grid Grid.Row="3">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="2*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button Grid.Column="0"
Content="Logout"
HorizontalAlignment="Stretch"
Command="{Binding Logout}"
Style="{StaticResource MaterialDesignFlatButton}"
Padding="0"
Margin="5" />
<Button Grid.Column="1"
Content="Unselect"
HorizontalAlignment="Stretch"
Command="{Binding UnselectFile}"
Style="{StaticResource MaterialDesignFlatButton}"
Padding="0"
Margin="5" />
<StackPanel Grid.Column="2"
Orientation="Horizontal"
VerticalAlignment="Center"
Margin="5">
<TextBlock Text="Refreshing in: " Foreground="#888888" />
<TextBlock Text="{Binding RefreshingIn}" Foreground="#888888"/>
</StackPanel>
<Button Grid.Column="3"
Content="New folder"
HorizontalAlignment="Stretch"
Command="{Binding Folder.Open}"
Style="{StaticResource MaterialDesignFlatButton}"
Padding="0"
Margin="5" />
<Button Grid.Column="4"
Content="Refresh"
HorizontalAlignment="Stretch"
Command="{Binding Refresh}"
Style="{StaticResource MaterialDesignFlatButton}"
Padding="0"
Margin="5" />
</Grid>
<Grid Grid.Row="1" Visibility="{Binding Auth.IsAnonymous, Converter={StaticResource BooleanToVisibility}}">
<views:AuthView DataContext="{Binding Auth}" />
</Grid>
</Grid>
</UserControl>

Просмотреть файл

@ -0,0 +1,32 @@
using Camelotia.Presentation.Interfaces;
using ReactiveUI;
using System.Windows;
using System.Windows.Controls;
namespace Camelotia.Presentation.Wpf.Views
{
public partial class ProviderView : UserControl, IViewFor<IProviderViewModel>
{
public static readonly DependencyProperty ViewModelProperty = DependencyProperty
.Register(nameof(ViewModel), typeof(IProviderViewModel), typeof(ProviderView), null);
public ProviderView()
{
InitializeComponent();
DataContextChanged += (sender, args) => ViewModel = DataContext as IProviderViewModel;
this.WhenActivated(disposables => { });
}
public IProviderViewModel ViewModel
{
get => (IProviderViewModel)GetValue(ViewModelProperty);
set => SetValue(ViewModelProperty, value);
}
object IViewFor.ViewModel
{
get => ViewModel;
set => ViewModel = (IProviderViewModel)value;
}
}
}

Просмотреть файл

@ -0,0 +1,55 @@
<UserControl
x:Class="Camelotia.Presentation.Wpf.Views.RenameFileView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
d:DesignHeight="450"
d:DesignWidth="800"
mc:Ignorable="d">
<StackPanel VerticalAlignment="Center"
HorizontalAlignment="Center"
Width="300">
<TextBlock Text="Rename File"
Foreground="#002171"
FontSize="16"
Margin="0 10" />
<ProgressBar HorizontalAlignment="Stretch"
IsIndeterminate="{Binding IsLoading}"
Visibility="{Binding IsLoading, Converter={StaticResource BooleanToVisibility}}"
Margin="0 5" />
<StackPanel Visibility="{Binding HasErrors, Converter={StaticResource BooleanToVisibility}}"
Background="#ffeeee"
Margin="0 5">
<StackPanel Margin="10">
<TextBlock Text="{Binding ErrorMessage}"
Foreground="#990000"
TextWrapping="Wrap" />
</StackPanel>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="0 5">
<TextBlock Text="Renaming file with name:" Margin="0 0 5 0" />
<TextBlock Text="{Binding OldName}" Foreground="#002171" />
</StackPanel>
<TextBlock Text="Please, enter new file name:" Margin="0 5" />
<TextBox Text="{Binding NewName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
materialDesign:HintAssist.Hint="Folder name" />
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="3*" />
<ColumnDefinition Width="2*" />
</Grid.ColumnDefinitions>
<Button Grid.Column="0"
Content="Rename file"
HorizontalAlignment="Stretch"
Command="{Binding Rename}"
Margin="0 10 10 10" />
<Button Grid.Column="1"
Content="Close"
HorizontalAlignment="Stretch"
Command="{Binding Close}"
Margin="0 10" />
</Grid>
</StackPanel>
</UserControl>

Просмотреть файл

@ -0,0 +1,32 @@
using Camelotia.Presentation.Interfaces;
using ReactiveUI;
using System.Windows;
using System.Windows.Controls;
namespace Camelotia.Presentation.Wpf.Views
{
public partial class RenameFileView : UserControl, IViewFor<IRenameFileViewModel>
{
public static readonly DependencyProperty ViewModelProperty = DependencyProperty
.Register(nameof(ViewModel), typeof(IRenameFileViewModel), typeof(RenameFileView), null);
public RenameFileView()
{
InitializeComponent();
DataContextChanged += (sender, args) => ViewModel = DataContext as IRenameFileViewModel;
this.WhenActivated(disposable => { });
}
public IRenameFileViewModel ViewModel
{
get => (IRenameFileViewModel)GetValue(ViewModelProperty);
set => SetValue(ViewModelProperty, value);
}
object IViewFor.ViewModel
{
get => ViewModel;
set => ViewModel = (IRenameFileViewModel)value;
}
}
}

115
src/Camelotia.Wpf.sln Normal file
Просмотреть файл

@ -0,0 +1,115 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.29009.5
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Camelotia.Services", "Camelotia.Services\Camelotia.Services.csproj", "{283B8F56-AB9F-4556-AB93-AAC54171841C}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Camelotia.Presentation", "Camelotia.Presentation\Camelotia.Presentation.csproj", "{777FBFA6-ECFA-42F5-AC5F-EFC4B2D4AE6B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Camelotia.Presentation.Tests", "Camelotia.Presentation.Tests\Camelotia.Presentation.Tests.csproj", "{AE41666B-41D1-4044-9752-7CD4460C1A90}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Camelotia.Presentation.Wpf", "Camelotia.Presentation.Wpf\Camelotia.Presentation.Wpf.csproj", "{E9EEEBF4-5F8D-480C-BD0A-9E5801189424}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|ARM = Debug|ARM
Debug|ARM64 = Debug|ARM64
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|ARM = Release|ARM
Release|ARM64 = Release|ARM64
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{283B8F56-AB9F-4556-AB93-AAC54171841C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{283B8F56-AB9F-4556-AB93-AAC54171841C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{283B8F56-AB9F-4556-AB93-AAC54171841C}.Debug|ARM.ActiveCfg = Debug|Any CPU
{283B8F56-AB9F-4556-AB93-AAC54171841C}.Debug|ARM.Build.0 = Debug|Any CPU
{283B8F56-AB9F-4556-AB93-AAC54171841C}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{283B8F56-AB9F-4556-AB93-AAC54171841C}.Debug|ARM64.Build.0 = Debug|Any CPU
{283B8F56-AB9F-4556-AB93-AAC54171841C}.Debug|x64.ActiveCfg = Debug|Any CPU
{283B8F56-AB9F-4556-AB93-AAC54171841C}.Debug|x64.Build.0 = Debug|Any CPU
{283B8F56-AB9F-4556-AB93-AAC54171841C}.Debug|x86.ActiveCfg = Debug|Any CPU
{283B8F56-AB9F-4556-AB93-AAC54171841C}.Debug|x86.Build.0 = Debug|Any CPU
{283B8F56-AB9F-4556-AB93-AAC54171841C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{283B8F56-AB9F-4556-AB93-AAC54171841C}.Release|Any CPU.Build.0 = Release|Any CPU
{283B8F56-AB9F-4556-AB93-AAC54171841C}.Release|ARM.ActiveCfg = Release|Any CPU
{283B8F56-AB9F-4556-AB93-AAC54171841C}.Release|ARM.Build.0 = Release|Any CPU
{283B8F56-AB9F-4556-AB93-AAC54171841C}.Release|ARM64.ActiveCfg = Release|Any CPU
{283B8F56-AB9F-4556-AB93-AAC54171841C}.Release|ARM64.Build.0 = Release|Any CPU
{283B8F56-AB9F-4556-AB93-AAC54171841C}.Release|x64.ActiveCfg = Release|Any CPU
{283B8F56-AB9F-4556-AB93-AAC54171841C}.Release|x64.Build.0 = Release|Any CPU
{283B8F56-AB9F-4556-AB93-AAC54171841C}.Release|x86.ActiveCfg = Release|Any CPU
{283B8F56-AB9F-4556-AB93-AAC54171841C}.Release|x86.Build.0 = Release|Any CPU
{777FBFA6-ECFA-42F5-AC5F-EFC4B2D4AE6B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{777FBFA6-ECFA-42F5-AC5F-EFC4B2D4AE6B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{777FBFA6-ECFA-42F5-AC5F-EFC4B2D4AE6B}.Debug|ARM.ActiveCfg = Debug|Any CPU
{777FBFA6-ECFA-42F5-AC5F-EFC4B2D4AE6B}.Debug|ARM.Build.0 = Debug|Any CPU
{777FBFA6-ECFA-42F5-AC5F-EFC4B2D4AE6B}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{777FBFA6-ECFA-42F5-AC5F-EFC4B2D4AE6B}.Debug|ARM64.Build.0 = Debug|Any CPU
{777FBFA6-ECFA-42F5-AC5F-EFC4B2D4AE6B}.Debug|x64.ActiveCfg = Debug|Any CPU
{777FBFA6-ECFA-42F5-AC5F-EFC4B2D4AE6B}.Debug|x64.Build.0 = Debug|Any CPU
{777FBFA6-ECFA-42F5-AC5F-EFC4B2D4AE6B}.Debug|x86.ActiveCfg = Debug|Any CPU
{777FBFA6-ECFA-42F5-AC5F-EFC4B2D4AE6B}.Debug|x86.Build.0 = Debug|Any CPU
{777FBFA6-ECFA-42F5-AC5F-EFC4B2D4AE6B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{777FBFA6-ECFA-42F5-AC5F-EFC4B2D4AE6B}.Release|Any CPU.Build.0 = Release|Any CPU
{777FBFA6-ECFA-42F5-AC5F-EFC4B2D4AE6B}.Release|ARM.ActiveCfg = Release|Any CPU
{777FBFA6-ECFA-42F5-AC5F-EFC4B2D4AE6B}.Release|ARM.Build.0 = Release|Any CPU
{777FBFA6-ECFA-42F5-AC5F-EFC4B2D4AE6B}.Release|ARM64.ActiveCfg = Release|Any CPU
{777FBFA6-ECFA-42F5-AC5F-EFC4B2D4AE6B}.Release|ARM64.Build.0 = Release|Any CPU
{777FBFA6-ECFA-42F5-AC5F-EFC4B2D4AE6B}.Release|x64.ActiveCfg = Release|Any CPU
{777FBFA6-ECFA-42F5-AC5F-EFC4B2D4AE6B}.Release|x64.Build.0 = Release|Any CPU
{777FBFA6-ECFA-42F5-AC5F-EFC4B2D4AE6B}.Release|x86.ActiveCfg = Release|Any CPU
{777FBFA6-ECFA-42F5-AC5F-EFC4B2D4AE6B}.Release|x86.Build.0 = Release|Any CPU
{AE41666B-41D1-4044-9752-7CD4460C1A90}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AE41666B-41D1-4044-9752-7CD4460C1A90}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AE41666B-41D1-4044-9752-7CD4460C1A90}.Debug|ARM.ActiveCfg = Debug|Any CPU
{AE41666B-41D1-4044-9752-7CD4460C1A90}.Debug|ARM.Build.0 = Debug|Any CPU
{AE41666B-41D1-4044-9752-7CD4460C1A90}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{AE41666B-41D1-4044-9752-7CD4460C1A90}.Debug|ARM64.Build.0 = Debug|Any CPU
{AE41666B-41D1-4044-9752-7CD4460C1A90}.Debug|x64.ActiveCfg = Debug|Any CPU
{AE41666B-41D1-4044-9752-7CD4460C1A90}.Debug|x64.Build.0 = Debug|Any CPU
{AE41666B-41D1-4044-9752-7CD4460C1A90}.Debug|x86.ActiveCfg = Debug|Any CPU
{AE41666B-41D1-4044-9752-7CD4460C1A90}.Debug|x86.Build.0 = Debug|Any CPU
{AE41666B-41D1-4044-9752-7CD4460C1A90}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AE41666B-41D1-4044-9752-7CD4460C1A90}.Release|Any CPU.Build.0 = Release|Any CPU
{AE41666B-41D1-4044-9752-7CD4460C1A90}.Release|ARM.ActiveCfg = Release|Any CPU
{AE41666B-41D1-4044-9752-7CD4460C1A90}.Release|ARM.Build.0 = Release|Any CPU
{AE41666B-41D1-4044-9752-7CD4460C1A90}.Release|ARM64.ActiveCfg = Release|Any CPU
{AE41666B-41D1-4044-9752-7CD4460C1A90}.Release|ARM64.Build.0 = Release|Any CPU
{AE41666B-41D1-4044-9752-7CD4460C1A90}.Release|x64.ActiveCfg = Release|Any CPU
{AE41666B-41D1-4044-9752-7CD4460C1A90}.Release|x64.Build.0 = Release|Any CPU
{AE41666B-41D1-4044-9752-7CD4460C1A90}.Release|x86.ActiveCfg = Release|Any CPU
{AE41666B-41D1-4044-9752-7CD4460C1A90}.Release|x86.Build.0 = Release|Any CPU
{E9EEEBF4-5F8D-480C-BD0A-9E5801189424}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E9EEEBF4-5F8D-480C-BD0A-9E5801189424}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E9EEEBF4-5F8D-480C-BD0A-9E5801189424}.Debug|ARM.ActiveCfg = Debug|Any CPU
{E9EEEBF4-5F8D-480C-BD0A-9E5801189424}.Debug|ARM.Build.0 = Debug|Any CPU
{E9EEEBF4-5F8D-480C-BD0A-9E5801189424}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{E9EEEBF4-5F8D-480C-BD0A-9E5801189424}.Debug|ARM64.Build.0 = Debug|Any CPU
{E9EEEBF4-5F8D-480C-BD0A-9E5801189424}.Debug|x64.ActiveCfg = Debug|Any CPU
{E9EEEBF4-5F8D-480C-BD0A-9E5801189424}.Debug|x64.Build.0 = Debug|Any CPU
{E9EEEBF4-5F8D-480C-BD0A-9E5801189424}.Debug|x86.ActiveCfg = Debug|Any CPU
{E9EEEBF4-5F8D-480C-BD0A-9E5801189424}.Debug|x86.Build.0 = Debug|Any CPU
{E9EEEBF4-5F8D-480C-BD0A-9E5801189424}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E9EEEBF4-5F8D-480C-BD0A-9E5801189424}.Release|Any CPU.Build.0 = Release|Any CPU
{E9EEEBF4-5F8D-480C-BD0A-9E5801189424}.Release|ARM.ActiveCfg = Release|Any CPU
{E9EEEBF4-5F8D-480C-BD0A-9E5801189424}.Release|ARM.Build.0 = Release|Any CPU
{E9EEEBF4-5F8D-480C-BD0A-9E5801189424}.Release|ARM64.ActiveCfg = Release|Any CPU
{E9EEEBF4-5F8D-480C-BD0A-9E5801189424}.Release|ARM64.Build.0 = Release|Any CPU
{E9EEEBF4-5F8D-480C-BD0A-9E5801189424}.Release|x64.ActiveCfg = Release|Any CPU
{E9EEEBF4-5F8D-480C-BD0A-9E5801189424}.Release|x64.Build.0 = Release|Any CPU
{E9EEEBF4-5F8D-480C-BD0A-9E5801189424}.Release|x86.ActiveCfg = Release|Any CPU
{E9EEEBF4-5F8D-480C-BD0A-9E5801189424}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {0CB49554-419C-45F0-B5EB-B36357AF2018}
EndGlobalSection
EndGlobal

Просмотреть файл

@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.28307.168
# Visual Studio Version 16
VisualStudioVersion = 16.0.29009.5
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Camelotia.Services", "Camelotia.Services\Camelotia.Services.csproj", "{283B8F56-AB9F-4556-AB93-AAC54171841C}"
EndProject
@ -17,6 +17,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Camelotia.Presentation.Xama
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Camelotia.Presentation.Xamarin", "Camelotia.Presentation.Xamarin\Camelotia.Presentation.Xamarin.csproj", "{F019715C-675A-463B-AF36-58585F6FA7DF}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Camelotia.Presentation.Wpf", "Camelotia.Presentation.Wpf\Camelotia.Presentation.Wpf.csproj", "{E9EEEBF4-5F8D-480C-BD0A-9E5801189424}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -187,6 +189,26 @@ Global
{F019715C-675A-463B-AF36-58585F6FA7DF}.Release|x64.Build.0 = Release|Any CPU
{F019715C-675A-463B-AF36-58585F6FA7DF}.Release|x86.ActiveCfg = Release|Any CPU
{F019715C-675A-463B-AF36-58585F6FA7DF}.Release|x86.Build.0 = Release|Any CPU
{E9EEEBF4-5F8D-480C-BD0A-9E5801189424}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E9EEEBF4-5F8D-480C-BD0A-9E5801189424}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E9EEEBF4-5F8D-480C-BD0A-9E5801189424}.Debug|ARM.ActiveCfg = Debug|Any CPU
{E9EEEBF4-5F8D-480C-BD0A-9E5801189424}.Debug|ARM.Build.0 = Debug|Any CPU
{E9EEEBF4-5F8D-480C-BD0A-9E5801189424}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{E9EEEBF4-5F8D-480C-BD0A-9E5801189424}.Debug|ARM64.Build.0 = Debug|Any CPU
{E9EEEBF4-5F8D-480C-BD0A-9E5801189424}.Debug|x64.ActiveCfg = Debug|Any CPU
{E9EEEBF4-5F8D-480C-BD0A-9E5801189424}.Debug|x64.Build.0 = Debug|Any CPU
{E9EEEBF4-5F8D-480C-BD0A-9E5801189424}.Debug|x86.ActiveCfg = Debug|Any CPU
{E9EEEBF4-5F8D-480C-BD0A-9E5801189424}.Debug|x86.Build.0 = Debug|Any CPU
{E9EEEBF4-5F8D-480C-BD0A-9E5801189424}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E9EEEBF4-5F8D-480C-BD0A-9E5801189424}.Release|Any CPU.Build.0 = Release|Any CPU
{E9EEEBF4-5F8D-480C-BD0A-9E5801189424}.Release|ARM.ActiveCfg = Release|Any CPU
{E9EEEBF4-5F8D-480C-BD0A-9E5801189424}.Release|ARM.Build.0 = Release|Any CPU
{E9EEEBF4-5F8D-480C-BD0A-9E5801189424}.Release|ARM64.ActiveCfg = Release|Any CPU
{E9EEEBF4-5F8D-480C-BD0A-9E5801189424}.Release|ARM64.Build.0 = Release|Any CPU
{E9EEEBF4-5F8D-480C-BD0A-9E5801189424}.Release|x64.ActiveCfg = Release|Any CPU
{E9EEEBF4-5F8D-480C-BD0A-9E5801189424}.Release|x64.Build.0 = Release|Any CPU
{E9EEEBF4-5F8D-480C-BD0A-9E5801189424}.Release|x86.ActiveCfg = Release|Any CPU
{E9EEEBF4-5F8D-480C-BD0A-9E5801189424}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE