feature: Use .NET 6, use new C# language features (#52)
* refactor: Use new C# features where possible * refactor: Use file scoped namespaces in UWP project * Use .NET 6, regenerate NukeBuild files
This commit is contained in:
Родитель
874ce5d56d
Коммит
ff18127f07
|
@ -0,0 +1,114 @@
|
|||
{
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"title": "Build Schema",
|
||||
"$ref": "#/definitions/build",
|
||||
"definitions": {
|
||||
"build": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"Configuration": {
|
||||
"type": "string"
|
||||
},
|
||||
"Continue": {
|
||||
"type": "boolean",
|
||||
"description": "Indicates to continue a previously failed build attempt"
|
||||
},
|
||||
"Full": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"Help": {
|
||||
"type": "boolean",
|
||||
"description": "Shows the help text for this build assembly"
|
||||
},
|
||||
"Host": {
|
||||
"type": "string",
|
||||
"description": "Host for execution. Default is 'automatic'",
|
||||
"enum": [
|
||||
"AppVeyor",
|
||||
"AzurePipelines",
|
||||
"Bamboo",
|
||||
"Bitrise",
|
||||
"GitHubActions",
|
||||
"GitLab",
|
||||
"Jenkins",
|
||||
"Rider",
|
||||
"SpaceAutomation",
|
||||
"TeamCity",
|
||||
"Terminal",
|
||||
"TravisCI",
|
||||
"VisualStudio",
|
||||
"VSCode"
|
||||
]
|
||||
},
|
||||
"Interactive": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"NoLogo": {
|
||||
"type": "boolean",
|
||||
"description": "Disables displaying the NUKE logo"
|
||||
},
|
||||
"Partition": {
|
||||
"type": "string",
|
||||
"description": "Partition to use on CI"
|
||||
},
|
||||
"Plan": {
|
||||
"type": "boolean",
|
||||
"description": "Shows the execution plan (HTML)"
|
||||
},
|
||||
"Profile": {
|
||||
"type": "array",
|
||||
"description": "Defines the profiles to load",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"Root": {
|
||||
"type": "string",
|
||||
"description": "Root directory during build execution"
|
||||
},
|
||||
"Skip": {
|
||||
"type": "array",
|
||||
"description": "List of targets to be skipped. Empty list skips all dependencies",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Clean",
|
||||
"CompileAvaloniaApp",
|
||||
"CompileUniversalWindowsApp",
|
||||
"CompileWindowsPresentationApp",
|
||||
"CompileXamarinAndroidApp",
|
||||
"RunInteractive",
|
||||
"RunUnitTests"
|
||||
]
|
||||
}
|
||||
},
|
||||
"Target": {
|
||||
"type": "array",
|
||||
"description": "List of targets to be invoked. Default is '{default_target}'",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Clean",
|
||||
"CompileAvaloniaApp",
|
||||
"CompileUniversalWindowsApp",
|
||||
"CompileWindowsPresentationApp",
|
||||
"CompileXamarinAndroidApp",
|
||||
"RunInteractive",
|
||||
"RunUnitTests"
|
||||
]
|
||||
}
|
||||
},
|
||||
"Verbosity": {
|
||||
"type": "string",
|
||||
"description": "Logging verbosity during build execution. Default is 'Normal'",
|
||||
"enum": [
|
||||
"Minimal",
|
||||
"Normal",
|
||||
"Quiet",
|
||||
"Verbose"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"$schema": "./build.schema.json",
|
||||
"Solution": "src/Camelotia.Xamarin.sln"
|
||||
}
|
|
@ -1,10 +1,16 @@
|
|||
jobs:
|
||||
- job: Linux
|
||||
pool:
|
||||
vmImage: 'ubuntu-18.04'
|
||||
vmImage: 'ubuntu-20.04'
|
||||
variables:
|
||||
buildConfiguration: 'Release'
|
||||
steps:
|
||||
- task: UseDotNet@2
|
||||
displayName: 'Install .NET 6 SDK'
|
||||
inputs:
|
||||
packageType: 'sdk'
|
||||
version: '6.0.x'
|
||||
performMultiLevelLookup: true
|
||||
- script: cd $(Build.SourcesDirectory) && bash ./build.sh
|
||||
displayName: 'Linux Build and Tests'
|
||||
- task: PublishTestResults@2
|
||||
|
@ -14,7 +20,7 @@ jobs:
|
|||
|
||||
- job: Windows
|
||||
pool:
|
||||
vmImage: 'windows-2019'
|
||||
vmImage: 'windows-2022'
|
||||
variables:
|
||||
buildConfiguration: 'Release'
|
||||
steps:
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
:; set -eo pipefail
|
||||
:; SCRIPT_DIR=$(cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd)
|
||||
:; ${SCRIPT_DIR}/build.sh "$@"
|
||||
:; exit $?
|
||||
|
||||
@ECHO OFF
|
||||
powershell -ExecutionPolicy ByPass -NoProfile -File "%~dp0build.ps1" %*
|
51
build.ps1
51
build.ps1
|
@ -4,9 +4,9 @@ Param(
|
|||
[string[]]$BuildArguments
|
||||
)
|
||||
|
||||
Write-Output "Windows PowerShell $($Host.Version)"
|
||||
Write-Output "PowerShell $($PSVersionTable.PSEdition) version $($PSVersionTable.PSVersion)"
|
||||
|
||||
Set-StrictMode -Version 2.0; $ErrorActionPreference = "Stop"; $ConfirmPreference = "None"; trap { exit 1 }
|
||||
Set-StrictMode -Version 2.0; $ErrorActionPreference = "Stop"; $ConfirmPreference = "None"; trap { Write-Error $_ -ErrorAction Continue; exit 1 }
|
||||
$PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent
|
||||
|
||||
###########################################################################
|
||||
|
@ -14,14 +14,15 @@ $PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent
|
|||
###########################################################################
|
||||
|
||||
$BuildProjectFile = "$PSScriptRoot\build\build.csproj"
|
||||
$TempDirectory = "$PSScriptRoot\\.tmp"
|
||||
$TempDirectory = "$PSScriptRoot\\.nuke\temp"
|
||||
|
||||
$DotNetGlobalFile = "$PSScriptRoot\\global.json"
|
||||
$DotNetInstallUrl = "https://raw.githubusercontent.com/dotnet/cli/master/scripts/obtain/dotnet-install.ps1"
|
||||
$DotNetInstallUrl = "https://dot.net/v1/dotnet-install.ps1"
|
||||
$DotNetChannel = "Current"
|
||||
|
||||
$env:DOTNET_SKIP_FIRST_TIME_EXPERIENCE = 1
|
||||
$env:DOTNET_CLI_TELEMETRY_OPTOUT = 1
|
||||
$env:DOTNET_MULTILEVEL_LOOKUP = 0
|
||||
|
||||
###########################################################################
|
||||
# EXECUTION
|
||||
|
@ -32,37 +33,37 @@ function ExecSafe([scriptblock] $cmd) {
|
|||
if ($LASTEXITCODE) { exit $LASTEXITCODE }
|
||||
}
|
||||
|
||||
# If global.json exists, load expected version
|
||||
if (Test-Path $DotNetGlobalFile) {
|
||||
$DotNetGlobal = $(Get-Content $DotNetGlobalFile | Out-String | ConvertFrom-Json)
|
||||
if ($DotNetGlobal.PSObject.Properties["sdk"] -and $DotNetGlobal.sdk.PSObject.Properties["version"]) {
|
||||
$DotNetVersion = $DotNetGlobal.sdk.version
|
||||
}
|
||||
}
|
||||
|
||||
# If dotnet is installed locally, and expected version is not set or installation matches the expected version
|
||||
if ((Get-Command "dotnet" -ErrorAction SilentlyContinue) -ne $null -and `
|
||||
(!(Test-Path variable:DotNetVersion) -or $(& dotnet --version) -eq $DotNetVersion)) {
|
||||
# If dotnet CLI is installed globally and it matches requested version, use for execution
|
||||
if ($null -ne (Get-Command "dotnet" -ErrorAction SilentlyContinue) -and `
|
||||
$(dotnet --version) -and $LASTEXITCODE -eq 0) {
|
||||
$env:DOTNET_EXE = (Get-Command "dotnet").Path
|
||||
}
|
||||
else {
|
||||
$DotNetDirectory = "$TempDirectory\dotnet-win"
|
||||
$env:DOTNET_EXE = "$DotNetDirectory\dotnet.exe"
|
||||
|
||||
# Download install script
|
||||
$DotNetInstallFile = "$TempDirectory\dotnet-install.ps1"
|
||||
md -force $TempDirectory > $null
|
||||
New-Item -ItemType Directory -Path $TempDirectory -Force | Out-Null
|
||||
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
|
||||
(New-Object System.Net.WebClient).DownloadFile($DotNetInstallUrl, $DotNetInstallFile)
|
||||
|
||||
# Install by channel or version
|
||||
if (!(Test-Path variable:DotNetVersion)) {
|
||||
ExecSafe { & $DotNetInstallFile -InstallDir $DotNetDirectory -Channel $DotNetChannel -NoPath }
|
||||
} else {
|
||||
ExecSafe { & $DotNetInstallFile -InstallDir $DotNetDirectory -Version $DotNetVersion -NoPath }
|
||||
# If global.json exists, load expected version
|
||||
if (Test-Path $DotNetGlobalFile) {
|
||||
$DotNetGlobal = $(Get-Content $DotNetGlobalFile | Out-String | ConvertFrom-Json)
|
||||
if ($DotNetGlobal.PSObject.Properties["sdk"] -and $DotNetGlobal.sdk.PSObject.Properties["version"]) {
|
||||
$DotNetVersion = $DotNetGlobal.sdk.version
|
||||
}
|
||||
}
|
||||
|
||||
# Install by channel or version
|
||||
$DotNetDirectory = "$TempDirectory\dotnet-win"
|
||||
if (!(Test-Path variable:DotNetVersion)) {
|
||||
ExecSafe { & powershell $DotNetInstallFile -InstallDir $DotNetDirectory -Channel $DotNetChannel -NoPath }
|
||||
} else {
|
||||
ExecSafe { & powershell $DotNetInstallFile -InstallDir $DotNetDirectory -Version $DotNetVersion -NoPath }
|
||||
}
|
||||
$env:DOTNET_EXE = "$DotNetDirectory\dotnet.exe"
|
||||
}
|
||||
|
||||
Write-Output "Microsoft (R) .NET Core SDK version $(& $env:DOTNET_EXE --version)"
|
||||
|
||||
ExecSafe { & $env:DOTNET_EXE build $BuildProjectFile /nodeReuse:false }
|
||||
ExecSafe { & $env:DOTNET_EXE build $BuildProjectFile /nodeReuse:false /p:UseSharedCompilation=false -nologo -clp:NoSummary --verbosity quiet }
|
||||
ExecSafe { & $env:DOTNET_EXE run --project $BuildProjectFile --no-build -- $BuildArguments }
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
echo $(bash --version 2>&1 | head -n 1)
|
||||
bash --version 2>&1 | head -n 1
|
||||
|
||||
set -eo pipefail
|
||||
SCRIPT_DIR=$(cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd)
|
||||
|
@ -10,53 +10,53 @@ SCRIPT_DIR=$(cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd)
|
|||
###########################################################################
|
||||
|
||||
BUILD_PROJECT_FILE="$SCRIPT_DIR/build/build.csproj"
|
||||
TEMP_DIRECTORY="$SCRIPT_DIR//.tmp"
|
||||
TEMP_DIRECTORY="$SCRIPT_DIR//.nuke/temp"
|
||||
|
||||
DOTNET_GLOBAL_FILE="$SCRIPT_DIR//global.json"
|
||||
DOTNET_INSTALL_URL="https://raw.githubusercontent.com/dotnet/cli/master/scripts/obtain/dotnet-install.sh"
|
||||
DOTNET_INSTALL_URL="https://dot.net/v1/dotnet-install.sh"
|
||||
DOTNET_CHANNEL="Current"
|
||||
|
||||
export DOTNET_CLI_TELEMETRY_OPTOUT=1
|
||||
export DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1
|
||||
export DOTNET_MULTILEVEL_LOOKUP=0
|
||||
|
||||
###########################################################################
|
||||
# EXECUTION
|
||||
###########################################################################
|
||||
|
||||
function FirstJsonValue {
|
||||
perl -nle 'print $1 if m{"'$1'": "([^"\-]+)",?}' <<< ${@:2}
|
||||
perl -nle 'print $1 if m{"'"$1"'": "([^"]+)",?}' <<< "${@:2}"
|
||||
}
|
||||
|
||||
# If global.json exists, load expected version
|
||||
if [ -f "$DOTNET_GLOBAL_FILE" ]; then
|
||||
DOTNET_VERSION=$(FirstJsonValue "version" $(cat "$DOTNET_GLOBAL_FILE"))
|
||||
if [ "$DOTNET_VERSION" == "" ]; then
|
||||
unset DOTNET_VERSION
|
||||
fi
|
||||
fi
|
||||
|
||||
# If dotnet is installed locally, and expected version is not set or installation matches the expected version
|
||||
if [[ -x "$(command -v dotnet)" && (-z ${DOTNET_VERSION+x} || $(dotnet --version) == "$DOTNET_VERSION") ]]; then
|
||||
# If dotnet CLI is installed globally and it matches requested version, use for execution
|
||||
if [ -x "$(command -v dotnet)" ] && dotnet --version &>/dev/null; then
|
||||
export DOTNET_EXE="$(command -v dotnet)"
|
||||
else
|
||||
DOTNET_DIRECTORY="$TEMP_DIRECTORY/dotnet-unix"
|
||||
export DOTNET_EXE="$DOTNET_DIRECTORY/dotnet"
|
||||
|
||||
# Download install script
|
||||
DOTNET_INSTALL_FILE="$TEMP_DIRECTORY/dotnet-install.sh"
|
||||
mkdir -p "$TEMP_DIRECTORY"
|
||||
curl -Lsfo "$DOTNET_INSTALL_FILE" "$DOTNET_INSTALL_URL"
|
||||
chmod +x "$DOTNET_INSTALL_FILE"
|
||||
|
||||
|
||||
# If global.json exists, load expected version
|
||||
if [[ -f "$DOTNET_GLOBAL_FILE" ]]; then
|
||||
DOTNET_VERSION=$(FirstJsonValue "version" "$(cat "$DOTNET_GLOBAL_FILE")")
|
||||
if [[ "$DOTNET_VERSION" == "" ]]; then
|
||||
unset DOTNET_VERSION
|
||||
fi
|
||||
fi
|
||||
|
||||
# Install by channel or version
|
||||
if [ -z ${DOTNET_VERSION+x} ]; then
|
||||
DOTNET_DIRECTORY="$TEMP_DIRECTORY/dotnet-unix"
|
||||
if [[ -z ${DOTNET_VERSION+x} ]]; then
|
||||
"$DOTNET_INSTALL_FILE" --install-dir "$DOTNET_DIRECTORY" --channel "$DOTNET_CHANNEL" --no-path
|
||||
else
|
||||
"$DOTNET_INSTALL_FILE" --install-dir "$DOTNET_DIRECTORY" --version "$DOTNET_VERSION" --no-path
|
||||
fi
|
||||
export DOTNET_EXE="$DOTNET_DIRECTORY/dotnet"
|
||||
fi
|
||||
|
||||
echo "Microsoft (R) .NET Core SDK version $("$DOTNET_EXE" --version)"
|
||||
|
||||
"$DOTNET_EXE" build "$BUILD_PROJECT_FILE" /nodeReuse:false
|
||||
"$DOTNET_EXE" build "$BUILD_PROJECT_FILE" /nodeReuse:false /p:UseSharedCompilation=false -nologo -clp:NoSummary --verbosity quiet
|
||||
"$DOTNET_EXE" run --project "$BUILD_PROJECT_FILE" --no-build -- "$@"
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
[*.cs]
|
||||
dotnet_style_qualification_for_field = false:warning
|
||||
dotnet_style_qualification_for_property = false:warning
|
||||
dotnet_style_qualification_for_method = false:warning
|
||||
dotnet_style_qualification_for_event = false:warning
|
||||
dotnet_style_require_accessibility_modifiers = never:warning
|
||||
|
||||
csharp_style_expression_bodied_methods = true:silent
|
||||
csharp_style_expression_bodied_properties = true:warning
|
||||
csharp_style_expression_bodied_indexers = true:warning
|
||||
csharp_style_expression_bodied_accessors = true:warning
|
|
@ -7,15 +7,14 @@ using Nuke.Common.Tools.DotNet;
|
|||
using Nuke.Common.Tools.MSBuild;
|
||||
using Nuke.Common.Utilities.Collections;
|
||||
using static Nuke.Common.IO.FileSystemTasks;
|
||||
using static Nuke.Common.IO.PathConstruction;
|
||||
using static Nuke.Common.Tools.DotNet.DotNetTasks;
|
||||
using static Nuke.Common.Tools.MSBuild.MSBuildTasks;
|
||||
|
||||
// ReSharper disable ArrangeTypeMemberModifiers
|
||||
|
||||
[CheckBuildProjectConfigurations]
|
||||
[CheckBuildProjectConfigurations(TimeoutInMilliseconds = 2000)]
|
||||
[UnsetVisualStudioEnvironmentVariables]
|
||||
internal class Build : NukeBuild
|
||||
class Build : NukeBuild
|
||||
{
|
||||
const string InteractiveProjectName = "Camelotia.Presentation.Avalonia";
|
||||
const string CoverageFileName = "coverage.cobertura.xml";
|
||||
|
@ -64,15 +63,15 @@ internal class Build : NukeBuild
|
|||
.Executes(() =>
|
||||
{
|
||||
var execute = EnvironmentInfo.IsWin && Full;
|
||||
Logger.Info($"Should compile for Universal Windows: {execute}");
|
||||
Serilog.Log.Information($"Should compile for Universal Windows: {execute}");
|
||||
if (!execute) return;
|
||||
|
||||
Logger.Normal("Restoring packages required by UAP...");
|
||||
Serilog.Log.Information("Restoring packages required by UAP...");
|
||||
var project = SourceDirectory.GlobFiles("**/*.Uwp.csproj").First();
|
||||
MSBuild(settings => settings
|
||||
.SetProjectFile(project)
|
||||
.SetTargets("Restore"));
|
||||
Logger.Success("Successfully restored UAP packages.");
|
||||
Serilog.Log.Information("Successfully restored UAP packages.");
|
||||
|
||||
new[] { MSBuildTargetPlatform.x86,
|
||||
MSBuildTargetPlatform.x64,
|
||||
|
@ -81,13 +80,13 @@ internal class Build : NukeBuild
|
|||
|
||||
void BuildApp(MSBuildTargetPlatform platform)
|
||||
{
|
||||
Logger.Normal("Cleaning UAP project...");
|
||||
Serilog.Log.Information("Cleaning UAP project...");
|
||||
MSBuild(settings => settings
|
||||
.SetProjectFile(project)
|
||||
.SetTargets("Clean"));
|
||||
Logger.Success("Successfully managed to clean UAP project.");
|
||||
Serilog.Log.Information("Successfully managed to clean UAP project.");
|
||||
|
||||
Logger.Normal($"Building UAP project for {platform}...");
|
||||
Serilog.Log.Information($"Building UAP project for {platform}...");
|
||||
MSBuild(settings => settings
|
||||
.SetProjectFile(project)
|
||||
.SetTargets("Build")
|
||||
|
@ -97,7 +96,7 @@ internal class Build : NukeBuild
|
|||
.SetProperty("AppxPackageDir", ArtifactsDirectory)
|
||||
.SetProperty("UapAppxPackageBuildMode", "CI")
|
||||
.SetProperty("AppxBundle", "Always"));
|
||||
Logger.Success($"Successfully built UAP project for {platform}.");
|
||||
Serilog.Log.Information($"Successfully built UAP project for {platform}.");
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -106,38 +105,38 @@ internal class Build : NukeBuild
|
|||
.Executes(() =>
|
||||
{
|
||||
var execute = EnvironmentInfo.IsWin && Full;
|
||||
Logger.Info($"Should compile for Android: {execute}");
|
||||
Serilog.Log.Information($"Should compile for Android: {execute}");
|
||||
if (!execute) return;
|
||||
|
||||
Logger.Normal("Restoring packages required by Xamarin Android...");
|
||||
Serilog.Log.Information("Restoring packages required by Xamarin Android...");
|
||||
var project = SourceDirectory.GlobFiles("**/*.Xamarin.Droid.csproj").First();
|
||||
MSBuild(settings => settings
|
||||
.SetProjectFile(project)
|
||||
.SetTargets("Restore"));
|
||||
Logger.Success("Successfully restored Xamarin Android packages.");
|
||||
Serilog.Log.Information("Successfully restored Xamarin Android packages.");
|
||||
|
||||
Logger.Normal("Building Xamarin Android project...");
|
||||
Serilog.Log.Information("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.");
|
||||
Serilog.Log.Information("Successfully built Xamarin Android project.");
|
||||
|
||||
Logger.Normal("Signing Android package...");
|
||||
Serilog.Log.Information("Signing Android package...");
|
||||
MSBuild(settings => settings
|
||||
.SetProjectFile(project)
|
||||
.SetTargets("SignAndroidPackage")
|
||||
.SetConfiguration(Configuration)
|
||||
.SetProperty("JavaSdkDirectory", java));
|
||||
Logger.Success("Successfully signed Xamarin Android APK.");
|
||||
Serilog.Log.Information("Successfully signed Xamarin Android APK.");
|
||||
|
||||
Logger.Normal("Moving APK files to artifacts directory...");
|
||||
Serilog.Log.Information("Moving APK files to artifacts directory...");
|
||||
SourceDirectory
|
||||
.GlobFiles("**/bin/**/*-Signed.apk")
|
||||
.ForEach(file => MoveFileToDirectory(file, ArtifactsDirectory));
|
||||
Logger.Success("Successfully moved APK files.");
|
||||
Serilog.Log.Information("Successfully moved APK files.");
|
||||
});
|
||||
|
||||
Target CompileWindowsPresentationApp => _ => _
|
||||
|
@ -145,22 +144,22 @@ internal class Build : NukeBuild
|
|||
.Executes(() =>
|
||||
{
|
||||
var execute = EnvironmentInfo.IsWin && Full;
|
||||
Logger.Info($"Should compile for WPF: {execute}");
|
||||
Serilog.Log.Information($"Should compile for WPF: {execute}");
|
||||
if (!execute) return;
|
||||
|
||||
Logger.Normal("Restoring packages required by WPF app...");
|
||||
Serilog.Log.Information("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.");
|
||||
Serilog.Log.Information("Successfully restored Wpf packages.");
|
||||
|
||||
Logger.Normal("Building WPF project...");
|
||||
Serilog.Log.Information("Building WPF project...");
|
||||
MSBuild(settings => settings
|
||||
.SetProjectFile(project)
|
||||
.SetTargets("Build")
|
||||
.SetConfiguration(Configuration));
|
||||
Logger.Success("Successfully built WPF project.");
|
||||
Serilog.Log.Information("Successfully built WPF project.");
|
||||
});
|
||||
|
||||
Target RunInteractive => _ => _
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using Nuke.Common.Tooling;
|
||||
|
||||
[TypeConverter(typeof(TypeConverter<Configuration>))]
|
||||
public class Configuration : Enumeration
|
||||
{
|
||||
public static Configuration Debug = new Configuration { Value = nameof(Debug) };
|
||||
public static Configuration Release = new Configuration { Value = nameof(Release) };
|
||||
|
||||
public static implicit operator string(Configuration configuration)
|
||||
{
|
||||
return configuration.Value;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
|
||||
<!-- This file prevents unintended imports of unrelated MSBuild files -->
|
||||
<!-- Uncomment to include parent Directory.Build.props file -->
|
||||
<!--<Import Project="$([MSBuild]::GetPathOfFileAbove('Directory.Build.props', '$(MSBuildThisFileDirectory)../'))" />-->
|
||||
|
||||
</Project>
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
|
||||
<!-- This file prevents unintended imports of unrelated MSBuild files -->
|
||||
<!-- Uncomment to include parent Directory.Build.targets file -->
|
||||
<!--<Import Project="$([MSBuild]::GetPathOfFileAbove('Directory.Build.targets', '$(MSBuildThisFileDirectory)../'))" />-->
|
||||
|
||||
</Project>
|
|
@ -2,33 +2,17 @@
|
|||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||
<RootNamespace />
|
||||
<IsPackable>False</IsPackable>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<RootNamespace></RootNamespace>
|
||||
<NoWarn>CS0649;CS0169</NoWarn>
|
||||
<NukeRootDirectory>..</NukeRootDirectory>
|
||||
<NukeScriptDirectory>..</NukeScriptDirectory>
|
||||
<NukeTelemetryVersion>1</NukeTelemetryVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Nuke.Common" Version="5.3.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<NukeSpecificationFiles Include="**\*.json" Exclude="bin\**;obj\**" />
|
||||
<NukeExternalFiles Include="**\*.*.ext" Exclude="bin\**;obj\**" />
|
||||
<None Remove="*.csproj.DotSettings;*.ref.*.txt" />
|
||||
|
||||
<!-- Common build related files -->
|
||||
<None Include="..\build.ps1" />
|
||||
<None Include="..\build.sh" />
|
||||
<None Include="..\.nuke" />
|
||||
<None Include="..\global.json" Condition="Exists('..\global.json')" />
|
||||
<None Include="..\nuget.config" Condition="Exists('..\nuget.config')" />
|
||||
<None Include="..\azure-pipelines.yml" Condition="Exists('..\azure-pipelines.yml')" />
|
||||
<None Include="..\Jenkinsfile" Condition="Exists('..\Jenkinsfile')" />
|
||||
<None Include="..\appveyor.yml" Condition="Exists('..\appveyor.yml')" />
|
||||
<None Include="..\.travis.yml" Condition="Exists('..\.travis.yml')" />
|
||||
<None Include="..\GitVersion.yml" Condition="Exists('..\GitVersion.yml')" />
|
||||
<PackageReference Include="Nuke.Common" Version="6.0.0" />
|
||||
<PackageDownload Include="GitVersion.Tool" Version="[5.8.0]" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=HeapView_002EDelegateAllocation/@EntryIndexedValue">DO_NOT_SHOW</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=VariableHidesOuterVariable/@EntryIndexedValue">DO_NOT_SHOW</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ClassNeverInstantiated_002EGlobal/@EntryIndexedValue">DO_NOT_SHOW</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=MemberCanBeMadeStatic_002ELocal/@EntryIndexedValue">DO_NOT_SHOW</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/DEFAULT_INTERNAL_MODIFIER/@EntryValue">Implicit</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/DEFAULT_PRIVATE_MODIFIER/@EntryValue">Implicit</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/METHOD_OR_OPERATOR_BODY/@EntryValue">ExpressionBody</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/ThisQualifier/INSTANCE_MEMBERS_QUALIFY_MEMBERS/@EntryValue">0</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/ANONYMOUS_METHOD_DECLARATION_BRACES/@EntryValue">NEXT_LINE</s:String>
|
||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/KEEP_USER_LINEBREAKS/@EntryValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_AFTER_INVOCATION_LPAR/@EntryValue">False</s:Boolean>
|
||||
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/MAX_ATTRIBUTE_LENGTH_FOR_SAME_LINE/@EntryValue">120</s:Int64>
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_FIELD_ATTRIBUTE_ON_SAME_LINE_EX/@EntryValue">IF_OWNER_IS_SINGLE_LINE</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/WRAP_ARGUMENTS_STYLE/@EntryValue">WRAP_IF_LONG</s:String>
|
||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_SIMPLE_ANONYMOUSMETHOD_ON_SINGLE_LINE/@EntryValue">False</s:Boolean>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateInstanceFields/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /></s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateStaticFields/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /></s:String>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpAttributeForSingleLineMethodUpgrade/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpKeepExistingMigration/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpPlaceEmbeddedOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpRenamePlacementToArrangementMigration/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpUseContinuousIndentInsideBracesMigration/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EAddAccessorOwnerDeclarationBracesMigration/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002ECSharpPlaceAttributeOnSameLineMigration/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateThisQualifierSettings/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
|
@ -1,9 +1,7 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Reactive;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Layout;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using Avalonia.ReactiveUI;
|
||||
using Camelotia.Presentation.AppState;
|
||||
|
@ -14,74 +12,73 @@ using Camelotia.Presentation.ViewModels;
|
|||
using Camelotia.Services;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace Camelotia.Presentation.Avalonia
|
||||
namespace Camelotia.Presentation.Avalonia;
|
||||
|
||||
public class App : Application
|
||||
{
|
||||
public class App : Application
|
||||
public override void Initialize() => AvaloniaXamlLoader.Load(this);
|
||||
|
||||
public override void OnFrameworkInitializationCompleted()
|
||||
{
|
||||
public override void Initialize() => AvaloniaXamlLoader.Load(this);
|
||||
Akavache.BlobCache.ApplicationName = "CamelotiaV2";
|
||||
var suspension = new AutoSuspendHelper(ApplicationLifetime);
|
||||
RxApp.SuspensionHost.CreateNewAppState = () => new MainState();
|
||||
RxApp.SuspensionHost.SetupDefaultSuspendResume(new NewtonsoftJsonSuspensionDriver("appstate.json"));
|
||||
suspension.OnFrameworkInitializationCompleted();
|
||||
|
||||
public override void OnFrameworkInitializationCompleted()
|
||||
var window = new Window
|
||||
{
|
||||
Akavache.BlobCache.ApplicationName = "CamelotiaV2";
|
||||
var suspension = new AutoSuspendHelper(ApplicationLifetime);
|
||||
RxApp.SuspensionHost.CreateNewAppState = () => new MainState();
|
||||
RxApp.SuspensionHost.SetupDefaultSuspendResume(new NewtonsoftJsonSuspensionDriver("appstate.json"));
|
||||
suspension.OnFrameworkInitializationCompleted();
|
||||
Height = 590,
|
||||
Width = 850,
|
||||
MinHeight = 590,
|
||||
MinWidth = 850,
|
||||
};
|
||||
|
||||
var window = new Window
|
||||
{
|
||||
Height = 590,
|
||||
Width = 850,
|
||||
MinHeight = 590,
|
||||
MinWidth = 850,
|
||||
};
|
||||
AttachDevTools(window);
|
||||
window.Content = CreateView(window);
|
||||
window.Show();
|
||||
|
||||
AttachDevTools(window);
|
||||
window.Content = CreateView(window);
|
||||
window.Show();
|
||||
RxApp.DefaultExceptionHandler = Observer.Create<Exception>(Console.WriteLine);
|
||||
base.OnFrameworkInitializationCompleted();
|
||||
}
|
||||
|
||||
RxApp.DefaultExceptionHandler = Observer.Create<Exception>(Console.WriteLine);
|
||||
base.OnFrameworkInitializationCompleted();
|
||||
}
|
||||
public object CreateView(Window window)
|
||||
{
|
||||
var view = new MainView();
|
||||
var styles = new AvaloniaStyleManager(view);
|
||||
view.SwitchThemeButton.Click += (_, _) => styles.UseNextTheme();
|
||||
view.DataContext ??= CreateViewModel(window);
|
||||
return view;
|
||||
}
|
||||
|
||||
public object CreateView(Window window)
|
||||
{
|
||||
var view = new MainView();
|
||||
var styles = new AvaloniaStyleManager(view);
|
||||
view.SwitchThemeButton.Click += (_, _) => styles.UseNextTheme();
|
||||
view.DataContext ??= CreateViewModel(window);
|
||||
return view;
|
||||
}
|
||||
private static MainViewModel CreateViewModel(Window window)
|
||||
{
|
||||
var main = RxApp.SuspensionHost.GetAppState<MainState>();
|
||||
return new MainViewModel(
|
||||
main,
|
||||
new CloudFactory(
|
||||
main.CloudConfiguration,
|
||||
new AvaloniaYandexAuthenticator(),
|
||||
Akavache.BlobCache.UserAccount),
|
||||
(state, provider) => new CloudViewModel(
|
||||
state,
|
||||
owner => new CreateFolderViewModel(state.CreateFolderState, owner, provider),
|
||||
owner => new RenameFileViewModel(state.RenameFileState, owner, provider),
|
||||
(file, owner) => new FileViewModel(owner, file),
|
||||
(folder, owner) => new FolderViewModel(owner, folder),
|
||||
new AuthViewModel(
|
||||
new DirectAuthViewModel(state.AuthState.DirectAuthState, provider),
|
||||
new HostAuthViewModel(state.AuthState.HostAuthState, provider),
|
||||
new OAuthViewModel(provider),
|
||||
provider),
|
||||
new AvaloniaFileManager(window),
|
||||
provider));
|
||||
}
|
||||
|
||||
private static MainViewModel CreateViewModel(Window window)
|
||||
{
|
||||
var main = RxApp.SuspensionHost.GetAppState<MainState>();
|
||||
return new MainViewModel(
|
||||
main,
|
||||
new CloudFactory(
|
||||
main.CloudConfiguration,
|
||||
new AvaloniaYandexAuthenticator(),
|
||||
Akavache.BlobCache.UserAccount),
|
||||
(state, provider) => new CloudViewModel(
|
||||
state,
|
||||
owner => new CreateFolderViewModel(state.CreateFolderState, owner, provider),
|
||||
owner => new RenameFileViewModel(state.RenameFileState, owner, provider),
|
||||
(file, owner) => new FileViewModel(owner, file),
|
||||
(folder, owner) => new FolderViewModel(owner, folder),
|
||||
new AuthViewModel(
|
||||
new DirectAuthViewModel(state.AuthState.DirectAuthState, provider),
|
||||
new HostAuthViewModel(state.AuthState.HostAuthState, provider),
|
||||
new OAuthViewModel(provider),
|
||||
provider),
|
||||
new AvaloniaFileManager(window),
|
||||
provider));
|
||||
}
|
||||
|
||||
private static void AttachDevTools(TopLevel window)
|
||||
{
|
||||
private static void AttachDevTools(TopLevel window)
|
||||
{
|
||||
#if DEBUG
|
||||
window.AttachDevTools();
|
||||
window.AttachDevTools();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<TargetFramework>net6</TargetFramework>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
</PropertyGroup>
|
||||
|
|
|
@ -1,16 +1,15 @@
|
|||
using Avalonia;
|
||||
using Avalonia.ReactiveUI;
|
||||
|
||||
namespace Camelotia.Presentation.Avalonia
|
||||
{
|
||||
public static class Program
|
||||
{
|
||||
public static void Main(string[] args) => BuildAvaloniaApp().StartWithClassicDesktopLifetime(args);
|
||||
namespace Camelotia.Presentation.Avalonia;
|
||||
|
||||
public static AppBuilder BuildAvaloniaApp()
|
||||
=> AppBuilder.Configure<App>()
|
||||
.UseReactiveUI()
|
||||
.UsePlatformDetect()
|
||||
.LogToTrace();
|
||||
}
|
||||
}
|
||||
public static class Program
|
||||
{
|
||||
public static void Main(string[] args) => BuildAvaloniaApp().StartWithClassicDesktopLifetime(args);
|
||||
|
||||
public static AppBuilder BuildAvaloniaApp()
|
||||
=> AppBuilder.Configure<App>()
|
||||
.UseReactiveUI()
|
||||
.UsePlatformDetect()
|
||||
.LogToTrace();
|
||||
}
|
|
@ -5,35 +5,34 @@ using System.Threading.Tasks;
|
|||
using Avalonia.Controls;
|
||||
using Camelotia.Services.Interfaces;
|
||||
|
||||
namespace Camelotia.Presentation.Avalonia.Services
|
||||
namespace Camelotia.Presentation.Avalonia.Services;
|
||||
|
||||
public sealed class AvaloniaFileManager : IFileManager
|
||||
{
|
||||
public sealed class AvaloniaFileManager : IFileManager
|
||||
private readonly Window _window;
|
||||
|
||||
public AvaloniaFileManager(Window window) => _window = window;
|
||||
|
||||
public async Task<Stream> OpenWrite(string name)
|
||||
{
|
||||
private readonly Window _window;
|
||||
var fileDialog = new OpenFolderDialog();
|
||||
var folder = await fileDialog.ShowAsync(_window).ConfigureAwait(false);
|
||||
var path = Path.Combine(folder, name);
|
||||
return File.Create(path);
|
||||
}
|
||||
|
||||
public AvaloniaFileManager(Window window) => _window = window;
|
||||
public async Task<(string Name, Stream Stream)> OpenRead()
|
||||
{
|
||||
var fileDialog = new OpenFileDialog { AllowMultiple = false };
|
||||
var files = await fileDialog.ShowAsync(_window).ConfigureAwait(false);
|
||||
var path = files.First();
|
||||
|
||||
public async Task<Stream> OpenWrite(string name)
|
||||
{
|
||||
var fileDialog = new OpenFolderDialog();
|
||||
var folder = await fileDialog.ShowAsync(_window).ConfigureAwait(false);
|
||||
var path = Path.Combine(folder, name);
|
||||
return File.Create(path);
|
||||
}
|
||||
var attributes = File.GetAttributes(path);
|
||||
var isFolder = attributes.HasFlag(FileAttributes.Directory);
|
||||
if (isFolder) throw new Exception("Folders are not supported.");
|
||||
|
||||
public async Task<(string Name, Stream Stream)> OpenRead()
|
||||
{
|
||||
var fileDialog = new OpenFileDialog { AllowMultiple = false };
|
||||
var files = await fileDialog.ShowAsync(_window).ConfigureAwait(false);
|
||||
var path = files.First();
|
||||
|
||||
var attributes = File.GetAttributes(path);
|
||||
var isFolder = attributes.HasFlag(FileAttributes.Directory);
|
||||
if (isFolder) throw new Exception("Folders are not supported.");
|
||||
|
||||
var stream = File.OpenRead(path);
|
||||
var name = Path.GetFileName(path);
|
||||
return (name, stream);
|
||||
}
|
||||
var stream = File.OpenRead(path);
|
||||
var name = Path.GetFileName(path);
|
||||
return (name, stream);
|
||||
}
|
||||
}
|
|
@ -2,68 +2,67 @@ using System;
|
|||
using Avalonia.Markup.Xaml.Styling;
|
||||
using Avalonia.Styling;
|
||||
|
||||
namespace Camelotia.Presentation.Avalonia.Services
|
||||
namespace Camelotia.Presentation.Avalonia.Services;
|
||||
|
||||
public sealed class AvaloniaStyleManager
|
||||
{
|
||||
public sealed class AvaloniaStyleManager
|
||||
public enum Theme
|
||||
{
|
||||
public enum Theme
|
||||
{
|
||||
Citrus,
|
||||
Sea,
|
||||
Rust,
|
||||
Candy,
|
||||
Magma
|
||||
}
|
||||
|
||||
private readonly StyleInclude _magmaStyle = CreateStyle("avares://Citrus.Avalonia/Magma.xaml");
|
||||
private readonly StyleInclude _candyStyle = CreateStyle("avares://Citrus.Avalonia/Candy.xaml");
|
||||
private readonly StyleInclude _citrusStyle = CreateStyle("avares://Citrus.Avalonia/Citrus.xaml");
|
||||
private readonly StyleInclude _rustStyle = CreateStyle("avares://Citrus.Avalonia/Rust.xaml");
|
||||
private readonly StyleInclude _seaStyle = CreateStyle("avares://Citrus.Avalonia/Sea.xaml");
|
||||
private readonly IStyleHost _window;
|
||||
|
||||
public AvaloniaStyleManager(IStyleHost window)
|
||||
{
|
||||
_window = window;
|
||||
if (window.Styles.Count == 0)
|
||||
window.Styles.Add(_seaStyle);
|
||||
else window.Styles[0] = _seaStyle;
|
||||
}
|
||||
|
||||
public Theme CurrentTheme { get; private set; } = Theme.Sea;
|
||||
|
||||
public void UseNextTheme() =>
|
||||
UseTheme(CurrentTheme switch
|
||||
{
|
||||
Theme.Citrus => Theme.Sea,
|
||||
Theme.Sea => Theme.Rust,
|
||||
Theme.Rust => Theme.Candy,
|
||||
Theme.Candy => Theme.Magma,
|
||||
Theme.Magma => Theme.Citrus,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(CurrentTheme))
|
||||
});
|
||||
|
||||
private static StyleInclude CreateStyle(string url)
|
||||
{
|
||||
var self = new Uri("resm:Styles?assembly=Citrus.Avalonia.Sandbox");
|
||||
return new StyleInclude(self)
|
||||
{
|
||||
Source = new Uri(url)
|
||||
};
|
||||
}
|
||||
|
||||
private void UseTheme(Theme theme)
|
||||
{
|
||||
CurrentTheme = theme;
|
||||
_window.Styles[0] = CurrentTheme switch
|
||||
{
|
||||
Theme.Citrus => _citrusStyle,
|
||||
Theme.Sea => _seaStyle,
|
||||
Theme.Rust => _rustStyle,
|
||||
Theme.Candy => _candyStyle,
|
||||
Theme.Magma => _magmaStyle,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(theme))
|
||||
};
|
||||
}
|
||||
Citrus,
|
||||
Sea,
|
||||
Rust,
|
||||
Candy,
|
||||
Magma
|
||||
}
|
||||
}
|
||||
|
||||
private readonly StyleInclude _magmaStyle = CreateStyle("avares://Citrus.Avalonia/Magma.xaml");
|
||||
private readonly StyleInclude _candyStyle = CreateStyle("avares://Citrus.Avalonia/Candy.xaml");
|
||||
private readonly StyleInclude _citrusStyle = CreateStyle("avares://Citrus.Avalonia/Citrus.xaml");
|
||||
private readonly StyleInclude _rustStyle = CreateStyle("avares://Citrus.Avalonia/Rust.xaml");
|
||||
private readonly StyleInclude _seaStyle = CreateStyle("avares://Citrus.Avalonia/Sea.xaml");
|
||||
private readonly IStyleHost _window;
|
||||
|
||||
public AvaloniaStyleManager(IStyleHost window)
|
||||
{
|
||||
_window = window;
|
||||
if (window.Styles.Count == 0)
|
||||
window.Styles.Add(_seaStyle);
|
||||
else window.Styles[0] = _seaStyle;
|
||||
}
|
||||
|
||||
public Theme CurrentTheme { get; private set; } = Theme.Sea;
|
||||
|
||||
public void UseNextTheme() =>
|
||||
UseTheme(CurrentTheme switch
|
||||
{
|
||||
Theme.Citrus => Theme.Sea,
|
||||
Theme.Sea => Theme.Rust,
|
||||
Theme.Rust => Theme.Candy,
|
||||
Theme.Candy => Theme.Magma,
|
||||
Theme.Magma => Theme.Citrus,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(CurrentTheme))
|
||||
});
|
||||
|
||||
private static StyleInclude CreateStyle(string url)
|
||||
{
|
||||
var self = new Uri("resm:Styles?assembly=Citrus.Avalonia.Sandbox");
|
||||
return new StyleInclude(self)
|
||||
{
|
||||
Source = new Uri(url)
|
||||
};
|
||||
}
|
||||
|
||||
private void UseTheme(Theme theme)
|
||||
{
|
||||
CurrentTheme = theme;
|
||||
_window.Styles[0] = CurrentTheme switch
|
||||
{
|
||||
Theme.Citrus => _citrusStyle,
|
||||
Theme.Sea => _seaStyle,
|
||||
Theme.Rust => _rustStyle,
|
||||
Theme.Candy => _candyStyle,
|
||||
Theme.Magma => _magmaStyle,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(theme))
|
||||
};
|
||||
}
|
||||
}
|
|
@ -5,23 +5,23 @@ using System.Text;
|
|||
using System.Threading.Tasks;
|
||||
using Camelotia.Services.Interfaces;
|
||||
|
||||
namespace Camelotia.Presentation.Avalonia.Services
|
||||
namespace Camelotia.Presentation.Avalonia.Services;
|
||||
|
||||
public sealed class AvaloniaYandexAuthenticator : IAuthenticator
|
||||
{
|
||||
public sealed class AvaloniaYandexAuthenticator : 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 returnUrl)
|
||||
{
|
||||
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 returnUrl)
|
||||
{
|
||||
var server = returnUrl.ToString();
|
||||
var listener = new HttpListener();
|
||||
listener.Prefixes.Add(server);
|
||||
listener.Start();
|
||||
new Process
|
||||
var server = returnUrl.ToString();
|
||||
var listener = new HttpListener();
|
||||
listener.Prefixes.Add(server);
|
||||
listener.Start();
|
||||
new Process
|
||||
{
|
||||
StartInfo = new ProcessStartInfo
|
||||
{
|
||||
|
@ -31,16 +31,15 @@ namespace Camelotia.Presentation.Avalonia.Services
|
|||
}
|
||||
.Start();
|
||||
|
||||
var context = await listener.GetContextAsync().ConfigureAwait(false);
|
||||
var code = context.Request.QueryString["code"];
|
||||
var context = await listener.GetContextAsync().ConfigureAwait(false);
|
||||
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).ConfigureAwait(false);
|
||||
var buffer = Encoding.UTF8.GetBytes(SuccessContent);
|
||||
context.Response.ContentLength64 = buffer.Length;
|
||||
await context.Response.OutputStream.WriteAsync(buffer, 0, buffer.Length).ConfigureAwait(false);
|
||||
|
||||
context.Response.Close();
|
||||
listener.Close();
|
||||
return code;
|
||||
}
|
||||
context.Response.Close();
|
||||
listener.Close();
|
||||
return code;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,37 +6,36 @@ using Avalonia.ReactiveUI;
|
|||
using Camelotia.Presentation.Interfaces;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace Camelotia.Presentation.Avalonia.Views
|
||||
{
|
||||
public sealed partial class AuthView : ReactiveUserControl<IAuthViewModel>
|
||||
{
|
||||
public AuthView()
|
||||
{
|
||||
InitializeComponent();
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
this.WhenAnyValue(x => x.ViewModel)
|
||||
.Where(context => context != null)
|
||||
.Select(ResolveControl)
|
||||
.BindTo(this, x => x.Content)
|
||||
.DisposeWith(disposables);
|
||||
});
|
||||
}
|
||||
namespace Camelotia.Presentation.Avalonia.Views;
|
||||
|
||||
private static IControl ResolveControl(IAuthViewModel context)
|
||||
public sealed partial class AuthView : ReactiveUserControl<IAuthViewModel>
|
||||
{
|
||||
public AuthView()
|
||||
{
|
||||
InitializeComponent();
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
if (context.SupportsDirectAuth)
|
||||
return new DirectAuthView { DataContext = context.DirectAuth };
|
||||
if (context.SupportsOAuth)
|
||||
return new OAuthView { DataContext = context.OAuth };
|
||||
if (context.SupportsHostAuth)
|
||||
return new HostAuthView { DataContext = context.HostAuth };
|
||||
return new TextBlock
|
||||
{
|
||||
Text = "No supported authentication method found.",
|
||||
HorizontalAlignment = HorizontalAlignment.Center,
|
||||
VerticalAlignment = VerticalAlignment.Center
|
||||
};
|
||||
}
|
||||
this.WhenAnyValue(x => x.ViewModel)
|
||||
.Where(context => context != null)
|
||||
.Select(ResolveControl)
|
||||
.BindTo(this, x => x.Content)
|
||||
.DisposeWith(disposables);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private static IControl ResolveControl(IAuthViewModel context)
|
||||
{
|
||||
if (context.SupportsDirectAuth)
|
||||
return new DirectAuthView { DataContext = context.DirectAuth };
|
||||
if (context.SupportsOAuth)
|
||||
return new OAuthView { DataContext = context.OAuth };
|
||||
if (context.SupportsHostAuth)
|
||||
return new HostAuthView { DataContext = context.HostAuth };
|
||||
return new TextBlock
|
||||
{
|
||||
Text = "No supported authentication method found.",
|
||||
HorizontalAlignment = HorizontalAlignment.Center,
|
||||
VerticalAlignment = VerticalAlignment.Center
|
||||
};
|
||||
}
|
||||
}
|
|
@ -2,14 +2,13 @@ using Avalonia.ReactiveUI;
|
|||
using Camelotia.Presentation.Interfaces;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace Camelotia.Presentation.Avalonia.Views
|
||||
namespace Camelotia.Presentation.Avalonia.Views;
|
||||
|
||||
public sealed partial class CreateFolderView : ReactiveUserControl<ICreateFolderViewModel>
|
||||
{
|
||||
public sealed partial class CreateFolderView : ReactiveUserControl<ICreateFolderViewModel>
|
||||
public CreateFolderView()
|
||||
{
|
||||
public CreateFolderView()
|
||||
{
|
||||
InitializeComponent();
|
||||
this.WhenActivated(disposables => { });
|
||||
}
|
||||
InitializeComponent();
|
||||
this.WhenActivated(disposables => { });
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,22 +4,21 @@ using Camelotia.Presentation.Interfaces;
|
|||
using ReactiveUI;
|
||||
using ReactiveUI.Validation.Extensions;
|
||||
|
||||
namespace Camelotia.Presentation.Avalonia.Views
|
||||
namespace Camelotia.Presentation.Avalonia.Views;
|
||||
|
||||
public sealed partial class DirectAuthView : ReactiveUserControl<IDirectAuthViewModel>
|
||||
{
|
||||
public sealed partial class DirectAuthView : ReactiveUserControl<IDirectAuthViewModel>
|
||||
public DirectAuthView()
|
||||
{
|
||||
public DirectAuthView()
|
||||
InitializeComponent();
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
InitializeComponent();
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
this.BindValidation(ViewModel, x => x.Username, x => x.UsernameValidation.Text)
|
||||
.DisposeWith(disposables);
|
||||
this.BindValidation(ViewModel, x => x.Password, x => x.PasswordValidation.Text)
|
||||
.DisposeWith(disposables);
|
||||
this.BindValidation(ViewModel, x => x.FormValidation.Text)
|
||||
.DisposeWith(disposables);
|
||||
});
|
||||
}
|
||||
this.BindValidation(ViewModel, x => x.Username, x => x.UsernameValidation.Text)
|
||||
.DisposeWith(disposables);
|
||||
this.BindValidation(ViewModel, x => x.Password, x => x.PasswordValidation.Text)
|
||||
.DisposeWith(disposables);
|
||||
this.BindValidation(ViewModel, x => x.FormValidation.Text)
|
||||
.DisposeWith(disposables);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,35 +2,32 @@ using System;
|
|||
using System.Reactive;
|
||||
using System.Reactive.Disposables;
|
||||
using System.Reactive.Linq;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.ReactiveUI;
|
||||
using Camelotia.Presentation.Interfaces;
|
||||
using ReactiveMarbles.ObservableEvents;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace Camelotia.Presentation.Avalonia.Views
|
||||
{
|
||||
public sealed partial class FileView : ReactiveUserControl<IFileViewModel>
|
||||
{
|
||||
public FileView()
|
||||
{
|
||||
InitializeComponent();
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
this.Events()
|
||||
.DoubleTapped
|
||||
.Do(args => ViewModel.Provider.SelectedFile = ViewModel)
|
||||
.Select(args => Unit.Default)
|
||||
.InvokeCommand(this, x => x.ViewModel.Provider.Open)
|
||||
.DisposeWith(disposables);
|
||||
namespace Camelotia.Presentation.Avalonia.Views;
|
||||
|
||||
this.ContextMenu
|
||||
.Events()
|
||||
.MenuOpened
|
||||
.Subscribe(args => ViewModel.Provider.SelectedFile = ViewModel)
|
||||
.DisposeWith(disposables);
|
||||
});
|
||||
}
|
||||
public sealed partial class FileView : ReactiveUserControl<IFileViewModel>
|
||||
{
|
||||
public FileView()
|
||||
{
|
||||
InitializeComponent();
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
this.Events()
|
||||
.DoubleTapped
|
||||
.Do(args => ViewModel.Provider.SelectedFile = ViewModel)
|
||||
.Select(args => Unit.Default)
|
||||
.InvokeCommand(this, x => x.ViewModel.Provider.Open)
|
||||
.DisposeWith(disposables);
|
||||
|
||||
this.ContextMenu
|
||||
.Events()
|
||||
.MenuOpened
|
||||
.Subscribe(args => ViewModel.Provider.SelectedFile = ViewModel)
|
||||
.DisposeWith(disposables);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,24 +4,23 @@ using Avalonia.ReactiveUI;
|
|||
using Camelotia.Presentation.Interfaces;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace Camelotia.Presentation.Avalonia.Views
|
||||
{
|
||||
public sealed partial class FolderView : ReactiveUserControl<IFolderViewModel>
|
||||
{
|
||||
public FolderView()
|
||||
{
|
||||
InitializeComponent();
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
this.WhenAnyValue(x => x.TopLevelMenu.IsSubMenuOpen)
|
||||
.BindTo(this, x => x.ArrowDown.IsVisible)
|
||||
.DisposeWith(disposables);
|
||||
namespace Camelotia.Presentation.Avalonia.Views;
|
||||
|
||||
this.WhenAnyValue(x => x.TopLevelMenu.IsSubMenuOpen)
|
||||
.Select(menuOpen => !menuOpen)
|
||||
.BindTo(this, x => x.ArrowRight.IsVisible)
|
||||
.DisposeWith(disposables);
|
||||
});
|
||||
}
|
||||
public sealed partial class FolderView : ReactiveUserControl<IFolderViewModel>
|
||||
{
|
||||
public FolderView()
|
||||
{
|
||||
InitializeComponent();
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
this.WhenAnyValue(x => x.TopLevelMenu.IsSubMenuOpen)
|
||||
.BindTo(this, x => x.ArrowDown.IsVisible)
|
||||
.DisposeWith(disposables);
|
||||
|
||||
this.WhenAnyValue(x => x.TopLevelMenu.IsSubMenuOpen)
|
||||
.Select(menuOpen => !menuOpen)
|
||||
.BindTo(this, x => x.ArrowRight.IsVisible)
|
||||
.DisposeWith(disposables);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,26 +4,25 @@ using Camelotia.Presentation.Interfaces;
|
|||
using ReactiveUI;
|
||||
using ReactiveUI.Validation.Extensions;
|
||||
|
||||
namespace Camelotia.Presentation.Avalonia.Views
|
||||
namespace Camelotia.Presentation.Avalonia.Views;
|
||||
|
||||
public sealed partial class HostAuthView : ReactiveUserControl<IHostAuthViewModel>
|
||||
{
|
||||
public sealed partial class HostAuthView : ReactiveUserControl<IHostAuthViewModel>
|
||||
public HostAuthView()
|
||||
{
|
||||
public HostAuthView()
|
||||
InitializeComponent();
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
InitializeComponent();
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
this.BindValidation(ViewModel, x => x.Address, x => x.AddressValidation.Text)
|
||||
.DisposeWith(disposables);
|
||||
this.BindValidation(ViewModel, x => x.Port, x => x.PortValidation.Text)
|
||||
.DisposeWith(disposables);
|
||||
this.BindValidation(ViewModel, x => x.Username, x => x.UsernameValidation.Text)
|
||||
.DisposeWith(disposables);
|
||||
this.BindValidation(ViewModel, x => x.Password, x => x.PasswordValidation.Text)
|
||||
.DisposeWith(disposables);
|
||||
this.BindValidation(ViewModel, x => x.FormValidation.Text)
|
||||
.DisposeWith(disposables);
|
||||
});
|
||||
}
|
||||
this.BindValidation(ViewModel, x => x.Address, x => x.AddressValidation.Text)
|
||||
.DisposeWith(disposables);
|
||||
this.BindValidation(ViewModel, x => x.Port, x => x.PortValidation.Text)
|
||||
.DisposeWith(disposables);
|
||||
this.BindValidation(ViewModel, x => x.Username, x => x.UsernameValidation.Text)
|
||||
.DisposeWith(disposables);
|
||||
this.BindValidation(ViewModel, x => x.Password, x => x.PasswordValidation.Text)
|
||||
.DisposeWith(disposables);
|
||||
this.BindValidation(ViewModel, x => x.FormValidation.Text)
|
||||
.DisposeWith(disposables);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,14 +2,13 @@ using Avalonia.ReactiveUI;
|
|||
using Camelotia.Presentation.Interfaces;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace Camelotia.Presentation.Avalonia.Views
|
||||
namespace Camelotia.Presentation.Avalonia.Views;
|
||||
|
||||
public sealed partial class MainView : ReactiveUserControl<IMainViewModel>
|
||||
{
|
||||
public sealed partial class MainView : ReactiveUserControl<IMainViewModel>
|
||||
public MainView()
|
||||
{
|
||||
public MainView()
|
||||
{
|
||||
InitializeComponent();
|
||||
this.WhenActivated(disposables => { });
|
||||
}
|
||||
InitializeComponent();
|
||||
this.WhenActivated(disposables => { });
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,14 +2,13 @@ using Avalonia.ReactiveUI;
|
|||
using Camelotia.Presentation.Interfaces;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace Camelotia.Presentation.Avalonia.Views
|
||||
namespace Camelotia.Presentation.Avalonia.Views;
|
||||
|
||||
public sealed partial class OAuthView : ReactiveUserControl<IOAuthViewModel>
|
||||
{
|
||||
public sealed partial class OAuthView : ReactiveUserControl<IOAuthViewModel>
|
||||
public OAuthView()
|
||||
{
|
||||
public OAuthView()
|
||||
{
|
||||
InitializeComponent();
|
||||
this.WhenActivated(disposables => { });
|
||||
}
|
||||
InitializeComponent();
|
||||
this.WhenActivated(disposables => { });
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,14 +2,13 @@ using Avalonia.ReactiveUI;
|
|||
using Camelotia.Presentation.Interfaces;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace Camelotia.Presentation.Avalonia.Views
|
||||
namespace Camelotia.Presentation.Avalonia.Views;
|
||||
|
||||
public sealed partial class ProviderView : ReactiveUserControl<ICloudViewModel>
|
||||
{
|
||||
public sealed partial class ProviderView : ReactiveUserControl<ICloudViewModel>
|
||||
public ProviderView()
|
||||
{
|
||||
public ProviderView()
|
||||
{
|
||||
InitializeComponent();
|
||||
this.WhenActivated(disposables => { });
|
||||
}
|
||||
InitializeComponent();
|
||||
this.WhenActivated(disposables => { });
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,14 +2,13 @@ using Avalonia.ReactiveUI;
|
|||
using Camelotia.Presentation.Interfaces;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace Camelotia.Presentation.Avalonia.Views
|
||||
namespace Camelotia.Presentation.Avalonia.Views;
|
||||
|
||||
public sealed partial class RenameFileView : ReactiveUserControl<IRenameFileViewModel>
|
||||
{
|
||||
public sealed partial class RenameFileView : ReactiveUserControl<IRenameFileViewModel>
|
||||
public RenameFileView()
|
||||
{
|
||||
public RenameFileView()
|
||||
{
|
||||
InitializeComponent();
|
||||
this.WhenActivated(disposables => { });
|
||||
}
|
||||
InitializeComponent();
|
||||
this.WhenActivated(disposables => { });
|
||||
}
|
||||
}
|
||||
}
|
|
@ -9,42 +9,41 @@ using Windows.UI.Xaml;
|
|||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Navigation;
|
||||
|
||||
namespace Camelotia.Presentation.Uwp
|
||||
namespace Camelotia.Presentation.Uwp;
|
||||
|
||||
public sealed partial class App : Application
|
||||
{
|
||||
public sealed partial class App : Application
|
||||
public App() => InitializeComponent();
|
||||
|
||||
protected override async void OnLaunched(LaunchActivatedEventArgs e)
|
||||
{
|
||||
public App() => InitializeComponent();
|
||||
var stateFile = await ApplicationData
|
||||
.Current.LocalFolder
|
||||
.CreateFileAsync("state.json", CreationCollisionOption.OpenIfExists);
|
||||
|
||||
protected override async void OnLaunched(LaunchActivatedEventArgs e)
|
||||
var autoSuspendHelper = new AutoSuspendHelper(this);
|
||||
RxApp.MainThreadScheduler = new SingleWindowDispatcherScheduler();
|
||||
RxApp.SuspensionHost.CreateNewAppState = () => new MainState();
|
||||
RxApp.SuspensionHost.SetupDefaultSuspendResume(new NewtonsoftJsonSuspensionDriver(stateFile.Path));
|
||||
autoSuspendHelper.OnLaunched(e);
|
||||
|
||||
if (!(Window.Current.Content is Frame rootFrame))
|
||||
{
|
||||
var stateFile = await ApplicationData
|
||||
.Current.LocalFolder
|
||||
.CreateFileAsync("state.json", CreationCollisionOption.OpenIfExists);
|
||||
|
||||
var autoSuspendHelper = new AutoSuspendHelper(this);
|
||||
RxApp.MainThreadScheduler = new SingleWindowDispatcherScheduler();
|
||||
RxApp.SuspensionHost.CreateNewAppState = () => new MainState();
|
||||
RxApp.SuspensionHost.SetupDefaultSuspendResume(new NewtonsoftJsonSuspensionDriver(stateFile.Path));
|
||||
autoSuspendHelper.OnLaunched(e);
|
||||
|
||||
if (!(Window.Current.Content is Frame rootFrame))
|
||||
{
|
||||
rootFrame = new Frame();
|
||||
rootFrame.NavigationFailed += OnNavigationFailed;
|
||||
Window.Current.Content = rootFrame;
|
||||
}
|
||||
|
||||
if (e.PrelaunchActivated == false)
|
||||
{
|
||||
if (rootFrame.Content == null)
|
||||
rootFrame.Navigate(typeof(MainView), e.Arguments);
|
||||
Window.Current.Activate();
|
||||
}
|
||||
rootFrame = new Frame();
|
||||
rootFrame.NavigationFailed += OnNavigationFailed;
|
||||
Window.Current.Content = rootFrame;
|
||||
}
|
||||
|
||||
private void OnNavigationFailed(object sender, NavigationFailedEventArgs e)
|
||||
if (e.PrelaunchActivated == false)
|
||||
{
|
||||
throw new Exception("Failed to load Page " + e.SourcePageType.FullName);
|
||||
if (rootFrame.Content == null)
|
||||
rootFrame.Navigate(typeof(MainView), e.Arguments);
|
||||
Window.Current.Activate();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnNavigationFailed(object sender, NavigationFailedEventArgs e)
|
||||
{
|
||||
throw new Exception("Failed to load Page " + e.SourcePageType.FullName);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,40 +6,39 @@ using Camelotia.Services;
|
|||
using Camelotia.Services.Models;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace Camelotia.Presentation.Uwp
|
||||
namespace Camelotia.Presentation.Uwp;
|
||||
|
||||
public sealed class Bootstrapper
|
||||
{
|
||||
public sealed class Bootstrapper
|
||||
public static IMainViewModel BuildMainViewModel()
|
||||
{
|
||||
public static IMainViewModel BuildMainViewModel()
|
||||
{
|
||||
var mainState = RxApp.SuspensionHost.GetAppState<MainState>();
|
||||
return new MainViewModel(
|
||||
mainState,
|
||||
new CloudFactory(
|
||||
mainState.CloudConfiguration,
|
||||
new UniversalWindowsYandexAuthenticator(),
|
||||
Akavache.BlobCache.UserAccount,
|
||||
new[]
|
||||
{
|
||||
CloudType.Yandex,
|
||||
CloudType.VkDocs,
|
||||
CloudType.Ftp,
|
||||
CloudType.Sftp,
|
||||
CloudType.GitHub
|
||||
}),
|
||||
(state, provider) => new CloudViewModel(
|
||||
state,
|
||||
owner => new CreateFolderViewModel(state.CreateFolderState, owner, provider),
|
||||
owner => new RenameFileViewModel(state.RenameFileState, owner, provider),
|
||||
(file, owner) => new FileViewModel(owner, file),
|
||||
(folder, owner) => new FolderViewModel(owner, folder),
|
||||
new AuthViewModel(
|
||||
new DirectAuthViewModel(state.AuthState.DirectAuthState, provider),
|
||||
new HostAuthViewModel(state.AuthState.HostAuthState, provider),
|
||||
new OAuthViewModel(provider),
|
||||
provider),
|
||||
new UniversalWindowsFileManager(),
|
||||
provider));
|
||||
}
|
||||
var mainState = RxApp.SuspensionHost.GetAppState<MainState>();
|
||||
return new MainViewModel(
|
||||
mainState,
|
||||
new CloudFactory(
|
||||
mainState.CloudConfiguration,
|
||||
new UniversalWindowsYandexAuthenticator(),
|
||||
Akavache.BlobCache.UserAccount,
|
||||
new[]
|
||||
{
|
||||
CloudType.Yandex,
|
||||
CloudType.VkDocs,
|
||||
CloudType.Ftp,
|
||||
CloudType.Sftp,
|
||||
CloudType.GitHub
|
||||
}),
|
||||
(state, provider) => new CloudViewModel(
|
||||
state,
|
||||
owner => new CreateFolderViewModel(state.CreateFolderState, owner, provider),
|
||||
owner => new RenameFileViewModel(state.RenameFileState, owner, provider),
|
||||
(file, owner) => new FileViewModel(owner, file),
|
||||
(folder, owner) => new FolderViewModel(owner, folder),
|
||||
new AuthViewModel(
|
||||
new DirectAuthViewModel(state.AuthState.DirectAuthState, provider),
|
||||
new HostAuthViewModel(state.AuthState.HostAuthState, provider),
|
||||
new OAuthViewModel(provider),
|
||||
provider),
|
||||
new UniversalWindowsFileManager(),
|
||||
provider));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,12 +11,13 @@
|
|||
<AssemblyName>Camelotia.Presentation.Uwp</AssemblyName>
|
||||
<DefaultLanguage>en-us</DefaultLanguage>
|
||||
<TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>
|
||||
<TargetPlatformVersion Condition=" '$(TargetPlatformVersion)' == '' ">10.0.18362.0</TargetPlatformVersion>
|
||||
<TargetPlatformVersion Condition=" '$(TargetPlatformVersion)' == '' ">10.0.19041.0</TargetPlatformVersion>
|
||||
<TargetPlatformMinVersion>10.0.18362.0</TargetPlatformMinVersion>
|
||||
<MinimumVisualStudioVersion>14</MinimumVisualStudioVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<ProjectTypeGuids>{A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||
<WindowsXamlEnableOverview>true</WindowsXamlEnableOverview>
|
||||
<LangVersion>latest</LangVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
|
|
|
@ -6,30 +6,29 @@ using Camelotia.Services.Interfaces;
|
|||
using Windows.Storage;
|
||||
using Windows.Storage.Pickers;
|
||||
|
||||
namespace Camelotia.Presentation.Uwp.Services
|
||||
{
|
||||
public sealed class UniversalWindowsFileManager : IFileManager
|
||||
{
|
||||
public async Task<(string Name, Stream Stream)> OpenRead()
|
||||
{
|
||||
var picker = new FileOpenPicker();
|
||||
picker.FileTypeFilter.Add("*");
|
||||
var file = await picker.PickSingleFileAsync();
|
||||
if (file == null) return (null, null);
|
||||
var stream = await file.OpenStreamForReadAsync().ConfigureAwait(false);
|
||||
return (file.Name, stream);
|
||||
}
|
||||
namespace Camelotia.Presentation.Uwp.Services;
|
||||
|
||||
public async Task<Stream> OpenWrite(string name)
|
||||
{
|
||||
var ext = Path.GetExtension(name);
|
||||
var picker = new FileSavePicker { SuggestedFileName = name };
|
||||
picker.FileTypeChoices.Add(ext, new List<string> { ext });
|
||||
var file = await picker.PickSaveFileAsync();
|
||||
if (file == null) return null;
|
||||
await FileIO.WriteTextAsync(file, string.Empty);
|
||||
var stream = await file.OpenStreamForWriteAsync().ConfigureAwait(false);
|
||||
return stream;
|
||||
}
|
||||
public sealed class UniversalWindowsFileManager : IFileManager
|
||||
{
|
||||
public async Task<(string Name, Stream Stream)> OpenRead()
|
||||
{
|
||||
var picker = new FileOpenPicker();
|
||||
picker.FileTypeFilter.Add("*");
|
||||
var file = await picker.PickSingleFileAsync();
|
||||
if (file == null) return (null, null);
|
||||
var stream = await file.OpenStreamForReadAsync().ConfigureAwait(false);
|
||||
return (file.Name, stream);
|
||||
}
|
||||
|
||||
public async Task<Stream> OpenWrite(string name)
|
||||
{
|
||||
var ext = Path.GetExtension(name);
|
||||
var picker = new FileSavePicker { SuggestedFileName = name };
|
||||
picker.FileTypeChoices.Add(ext, new List<string> { ext });
|
||||
var file = await picker.PickSaveFileAsync();
|
||||
if (file == null) return null;
|
||||
await FileIO.WriteTextAsync(file, string.Empty);
|
||||
var stream = await file.OpenStreamForWriteAsync().ConfigureAwait(false);
|
||||
return stream;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,70 +6,69 @@ using Windows.UI.Xaml;
|
|||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Media;
|
||||
|
||||
namespace Camelotia.Presentation.Uwp.Services
|
||||
namespace Camelotia.Presentation.Uwp.Services;
|
||||
|
||||
public sealed class UniversalWindowsYandexAuthenticator : IAuthenticator
|
||||
{
|
||||
public sealed class UniversalWindowsYandexAuthenticator : IAuthenticator
|
||||
private TaskCompletionSource<string> _taskCompletionSource;
|
||||
|
||||
public GrantType GrantType => GrantType.AccessToken;
|
||||
|
||||
public Task<string> ReceiveCode(Uri uri, Uri returnUri) => throw new PlatformNotSupportedException();
|
||||
|
||||
public async Task<string> ReceiveToken(Uri uri)
|
||||
{
|
||||
private TaskCompletionSource<string> _taskCompletionSource;
|
||||
|
||||
public GrantType GrantType => GrantType.AccessToken;
|
||||
|
||||
public Task<string> ReceiveCode(Uri uri, Uri returnUri) => throw new PlatformNotSupportedException();
|
||||
|
||||
public async Task<string> ReceiveToken(Uri uri)
|
||||
_taskCompletionSource = new TaskCompletionSource<string>();
|
||||
await WebView.ClearTemporaryWebDataAsync();
|
||||
await Window.Current.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
|
||||
{
|
||||
_taskCompletionSource = new TaskCompletionSource<string>();
|
||||
await WebView.ClearTemporaryWebDataAsync();
|
||||
await Window.Current.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
|
||||
{
|
||||
var root = Window.Current.Content;
|
||||
var web = FindControl<WebView>(root);
|
||||
if (web == null) throw new Exception("WebView named AuthenticationWebView wasn't found.");
|
||||
var root = Window.Current.Content;
|
||||
var web = FindControl<WebView>(root);
|
||||
if (web == null) throw new Exception("WebView named AuthenticationWebView wasn't found.");
|
||||
|
||||
web.Visibility = Visibility.Visible;
|
||||
web.NavigationCompleted += OnNavigationCompleted;
|
||||
web.Navigate(uri);
|
||||
});
|
||||
web.Visibility = Visibility.Visible;
|
||||
web.NavigationCompleted += OnNavigationCompleted;
|
||||
web.Navigate(uri);
|
||||
});
|
||||
|
||||
return await _taskCompletionSource.Task.ConfigureAwait(false);
|
||||
return await _taskCompletionSource.Task.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private static TControl FindControl<TControl>(UIElement parent)
|
||||
where TControl : FrameworkElement
|
||||
{
|
||||
var targetType = typeof(TControl);
|
||||
if (parent == null) return null;
|
||||
if (parent.GetType() == targetType)
|
||||
return (TControl)parent;
|
||||
|
||||
var result = default(TControl);
|
||||
var count = VisualTreeHelper.GetChildrenCount(parent);
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
var child = (UIElement)VisualTreeHelper.GetChild(parent, i);
|
||||
var rec = FindControl<TControl>(child);
|
||||
if (rec == null) continue;
|
||||
result = rec;
|
||||
break;
|
||||
}
|
||||
|
||||
private static TControl FindControl<TControl>(UIElement parent)
|
||||
where TControl : FrameworkElement
|
||||
{
|
||||
var targetType = typeof(TControl);
|
||||
if (parent == null) return null;
|
||||
if (parent.GetType() == targetType)
|
||||
return (TControl)parent;
|
||||
return result;
|
||||
}
|
||||
|
||||
var result = default(TControl);
|
||||
var count = VisualTreeHelper.GetChildrenCount(parent);
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
var child = (UIElement)VisualTreeHelper.GetChild(parent, i);
|
||||
var rec = FindControl<TControl>(child);
|
||||
if (rec == null) continue;
|
||||
result = rec;
|
||||
break;
|
||||
}
|
||||
private void OnNavigationCompleted(WebView sender, WebViewNavigationCompletedEventArgs args)
|
||||
{
|
||||
var currentUriString = args.Uri.ToString();
|
||||
if (!currentUriString.Contains("#"))
|
||||
return;
|
||||
|
||||
return result;
|
||||
}
|
||||
sender.NavigationCompleted -= OnNavigationCompleted;
|
||||
var token = currentUriString
|
||||
.Split('#')[1]
|
||||
.Split('&')[0]
|
||||
.Split('=')[1];
|
||||
|
||||
private void OnNavigationCompleted(WebView sender, WebViewNavigationCompletedEventArgs args)
|
||||
{
|
||||
var currentUriString = args.Uri.ToString();
|
||||
if (!currentUriString.Contains("#"))
|
||||
return;
|
||||
|
||||
sender.NavigationCompleted -= OnNavigationCompleted;
|
||||
var token = currentUriString
|
||||
.Split('#')[1]
|
||||
.Split('&')[0]
|
||||
.Split('=')[1];
|
||||
|
||||
_taskCompletionSource.SetResult(token);
|
||||
sender.Visibility = Visibility.Collapsed;
|
||||
}
|
||||
_taskCompletionSource.SetResult(token);
|
||||
sender.Visibility = Visibility.Collapsed;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,52 +6,51 @@ using ReactiveUI;
|
|||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
|
||||
namespace Camelotia.Presentation.Uwp.Views
|
||||
namespace Camelotia.Presentation.Uwp.Views;
|
||||
|
||||
public sealed partial class AuthView : UserControl, IViewFor<IAuthViewModel>
|
||||
{
|
||||
public sealed partial class AuthView : UserControl, IViewFor<IAuthViewModel>
|
||||
public static readonly DependencyProperty ViewModelProperty = DependencyProperty
|
||||
.Register(nameof(ViewModel), typeof(IAuthViewModel), typeof(AuthView), null);
|
||||
|
||||
public AuthView()
|
||||
{
|
||||
public static readonly DependencyProperty ViewModelProperty = DependencyProperty
|
||||
.Register(nameof(ViewModel), typeof(IAuthViewModel), typeof(AuthView), null);
|
||||
|
||||
public AuthView()
|
||||
InitializeComponent();
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
InitializeComponent();
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
this.WhenAnyValue(x => x.ViewModel.SupportsDirectAuth)
|
||||
.Where(supports => supports)
|
||||
.Subscribe(supports => AuthorizationPivot.SelectedIndex = 0)
|
||||
.DisposeWith(disposables);
|
||||
this.WhenAnyValue(x => x.ViewModel.SupportsDirectAuth)
|
||||
.Where(supports => supports)
|
||||
.Subscribe(supports => AuthorizationPivot.SelectedIndex = 0)
|
||||
.DisposeWith(disposables);
|
||||
|
||||
this.WhenAnyValue(x => x.ViewModel.SupportsOAuth)
|
||||
.Where(supports => supports)
|
||||
.Subscribe(supports => AuthorizationPivot.SelectedIndex = 1)
|
||||
.DisposeWith(disposables);
|
||||
this.WhenAnyValue(x => x.ViewModel.SupportsOAuth)
|
||||
.Where(supports => supports)
|
||||
.Subscribe(supports => AuthorizationPivot.SelectedIndex = 1)
|
||||
.DisposeWith(disposables);
|
||||
|
||||
this.WhenAnyValue(x => x.ViewModel.SupportsHostAuth)
|
||||
.Where(supports => supports)
|
||||
.Subscribe(supports => AuthorizationPivot.SelectedIndex = 2)
|
||||
.DisposeWith(disposables);
|
||||
this.WhenAnyValue(x => x.ViewModel.SupportsHostAuth)
|
||||
.Where(supports => supports)
|
||||
.Subscribe(supports => AuthorizationPivot.SelectedIndex = 2)
|
||||
.DisposeWith(disposables);
|
||||
|
||||
this.WhenAnyValue(
|
||||
this.WhenAnyValue(
|
||||
x => x.ViewModel.SupportsDirectAuth,
|
||||
x => x.ViewModel.SupportsHostAuth,
|
||||
x => x.ViewModel.SupportsOAuth)
|
||||
.Subscribe(x => AuthorizationPivot.Visibility = Visibility.Visible)
|
||||
.DisposeWith(disposables);
|
||||
});
|
||||
}
|
||||
.Subscribe(x => AuthorizationPivot.Visibility = Visibility.Visible)
|
||||
.DisposeWith(disposables);
|
||||
});
|
||||
}
|
||||
|
||||
public IAuthViewModel ViewModel
|
||||
{
|
||||
get => (IAuthViewModel)GetValue(ViewModelProperty);
|
||||
set => SetValue(ViewModelProperty, value);
|
||||
}
|
||||
public IAuthViewModel ViewModel
|
||||
{
|
||||
get => (IAuthViewModel)GetValue(ViewModelProperty);
|
||||
set => SetValue(ViewModelProperty, value);
|
||||
}
|
||||
|
||||
object IViewFor.ViewModel
|
||||
{
|
||||
get => ViewModel;
|
||||
set => ViewModel = (IAuthViewModel)value;
|
||||
}
|
||||
object IViewFor.ViewModel
|
||||
{
|
||||
get => ViewModel;
|
||||
set => ViewModel = (IAuthViewModel)value;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,29 +3,28 @@ using ReactiveUI;
|
|||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
|
||||
namespace Camelotia.Presentation.Uwp.Views
|
||||
namespace Camelotia.Presentation.Uwp.Views;
|
||||
|
||||
public sealed partial class CloudView : UserControl, IViewFor<ICloudViewModel>
|
||||
{
|
||||
public sealed partial class CloudView : UserControl, IViewFor<ICloudViewModel>
|
||||
public static readonly DependencyProperty ViewModelProperty = DependencyProperty
|
||||
.Register(nameof(ViewModel), typeof(ICloudViewModel), typeof(CloudView), null);
|
||||
|
||||
public CloudView()
|
||||
{
|
||||
public static readonly DependencyProperty ViewModelProperty = DependencyProperty
|
||||
.Register(nameof(ViewModel), typeof(ICloudViewModel), typeof(CloudView), null);
|
||||
InitializeComponent();
|
||||
this.WhenActivated(disposables => { });
|
||||
}
|
||||
|
||||
public CloudView()
|
||||
{
|
||||
InitializeComponent();
|
||||
this.WhenActivated(disposables => { });
|
||||
}
|
||||
public ICloudViewModel ViewModel
|
||||
{
|
||||
get => (ICloudViewModel)GetValue(ViewModelProperty);
|
||||
set => SetValue(ViewModelProperty, value);
|
||||
}
|
||||
|
||||
public ICloudViewModel ViewModel
|
||||
{
|
||||
get => (ICloudViewModel)GetValue(ViewModelProperty);
|
||||
set => SetValue(ViewModelProperty, value);
|
||||
}
|
||||
|
||||
object IViewFor.ViewModel
|
||||
{
|
||||
get => ViewModel;
|
||||
set => ViewModel = (ICloudViewModel)value;
|
||||
}
|
||||
object IViewFor.ViewModel
|
||||
{
|
||||
get => ViewModel;
|
||||
set => ViewModel = (ICloudViewModel)value;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,42 +7,41 @@ using ReactiveUI.Validation.Formatters;
|
|||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
|
||||
namespace Camelotia.Presentation.Uwp.Views
|
||||
namespace Camelotia.Presentation.Uwp.Views;
|
||||
|
||||
public sealed partial class CreateFolderView : UserControl, IViewFor<ICreateFolderViewModel>
|
||||
{
|
||||
public sealed partial class CreateFolderView : UserControl, IViewFor<ICreateFolderViewModel>
|
||||
public static readonly DependencyProperty ViewModelProperty = DependencyProperty
|
||||
.Register(nameof(ViewModel), typeof(ICreateFolderViewModel), typeof(CreateFolderView), null);
|
||||
|
||||
public CreateFolderView()
|
||||
{
|
||||
public static readonly DependencyProperty ViewModelProperty = DependencyProperty
|
||||
.Register(nameof(ViewModel), typeof(ICreateFolderViewModel), typeof(CreateFolderView), null);
|
||||
|
||||
public CreateFolderView()
|
||||
InitializeComponent();
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
InitializeComponent();
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
this.BindValidation(ViewModel, x => x.Name, x => x.FolderNameErrorLabel.Text)
|
||||
.DisposeWith(disposables);
|
||||
this.BindValidation(ViewModel, x => x.FormErrorLabel.Text, new SingleLineFormatter(Environment.NewLine))
|
||||
.DisposeWith(disposables);
|
||||
this.BindValidation(ViewModel, x => x.Name, x => x.FolderNameErrorLabel.Text)
|
||||
.DisposeWith(disposables);
|
||||
this.BindValidation(ViewModel, x => x.FormErrorLabel.Text, new SingleLineFormatter(Environment.NewLine))
|
||||
.DisposeWith(disposables);
|
||||
|
||||
this.WhenAnyValue(x => x.FolderNameErrorLabel.Text, text => !string.IsNullOrWhiteSpace(text))
|
||||
.BindTo(this, x => x.FolderNameErrorLabel.Visibility)
|
||||
.DisposeWith(disposables);
|
||||
this.WhenAnyValue(x => x.FormErrorLabel.Text, text => !string.IsNullOrWhiteSpace(text))
|
||||
.BindTo(this, x => x.FormErrorLabel.Visibility)
|
||||
.DisposeWith(disposables);
|
||||
});
|
||||
}
|
||||
this.WhenAnyValue(x => x.FolderNameErrorLabel.Text, text => !string.IsNullOrWhiteSpace(text))
|
||||
.BindTo(this, x => x.FolderNameErrorLabel.Visibility)
|
||||
.DisposeWith(disposables);
|
||||
this.WhenAnyValue(x => x.FormErrorLabel.Text, text => !string.IsNullOrWhiteSpace(text))
|
||||
.BindTo(this, x => x.FormErrorLabel.Visibility)
|
||||
.DisposeWith(disposables);
|
||||
});
|
||||
}
|
||||
|
||||
public ICreateFolderViewModel ViewModel
|
||||
{
|
||||
get => (ICreateFolderViewModel)GetValue(ViewModelProperty);
|
||||
set => SetValue(ViewModelProperty, value);
|
||||
}
|
||||
public ICreateFolderViewModel ViewModel
|
||||
{
|
||||
get => (ICreateFolderViewModel)GetValue(ViewModelProperty);
|
||||
set => SetValue(ViewModelProperty, value);
|
||||
}
|
||||
|
||||
object IViewFor.ViewModel
|
||||
{
|
||||
get => ViewModel;
|
||||
set => ViewModel = (ICreateFolderViewModel)value;
|
||||
}
|
||||
object IViewFor.ViewModel
|
||||
{
|
||||
get => ViewModel;
|
||||
set => ViewModel = (ICreateFolderViewModel)value;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,47 +7,46 @@ using ReactiveUI.Validation.Formatters;
|
|||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
|
||||
namespace Camelotia.Presentation.Uwp.Views
|
||||
namespace Camelotia.Presentation.Uwp.Views;
|
||||
|
||||
public sealed partial class DirectAuthView : UserControl, IViewFor<IDirectAuthViewModel>
|
||||
{
|
||||
public sealed partial class DirectAuthView : UserControl, IViewFor<IDirectAuthViewModel>
|
||||
public static readonly DependencyProperty ViewModelProperty = DependencyProperty
|
||||
.Register(nameof(ViewModel), typeof(IDirectAuthViewModel), typeof(DirectAuthView), null);
|
||||
|
||||
public DirectAuthView()
|
||||
{
|
||||
public static readonly DependencyProperty ViewModelProperty = DependencyProperty
|
||||
.Register(nameof(ViewModel), typeof(IDirectAuthViewModel), typeof(DirectAuthView), null);
|
||||
|
||||
public DirectAuthView()
|
||||
InitializeComponent();
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
InitializeComponent();
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
this.BindValidation(ViewModel, x => x.Username, x => x.UserNameErrorLabel.Text)
|
||||
.DisposeWith(disposables);
|
||||
this.BindValidation(ViewModel, x => x.Password, x => x.PasswordErrorLabel.Text)
|
||||
.DisposeWith(disposables);
|
||||
this.BindValidation(ViewModel, x => x.FormErrorLabel.Text, new SingleLineFormatter(Environment.NewLine))
|
||||
.DisposeWith(disposables);
|
||||
this.BindValidation(ViewModel, x => x.Username, x => x.UserNameErrorLabel.Text)
|
||||
.DisposeWith(disposables);
|
||||
this.BindValidation(ViewModel, x => x.Password, x => x.PasswordErrorLabel.Text)
|
||||
.DisposeWith(disposables);
|
||||
this.BindValidation(ViewModel, x => x.FormErrorLabel.Text, new SingleLineFormatter(Environment.NewLine))
|
||||
.DisposeWith(disposables);
|
||||
|
||||
this.WhenAnyValue(x => x.UserNameErrorLabel.Text, text => !string.IsNullOrWhiteSpace(text))
|
||||
.BindTo(this, x => x.UserNameErrorLabel.Visibility)
|
||||
.DisposeWith(disposables);
|
||||
this.WhenAnyValue(x => x.PasswordErrorLabel.Text, text => !string.IsNullOrWhiteSpace(text))
|
||||
.BindTo(this, x => x.PasswordErrorLabel.Visibility)
|
||||
.DisposeWith(disposables);
|
||||
this.WhenAnyValue(x => x.FormErrorLabel.Text, text => !string.IsNullOrWhiteSpace(text))
|
||||
.BindTo(this, x => x.FormErrorLabel.Visibility)
|
||||
.DisposeWith(disposables);
|
||||
});
|
||||
}
|
||||
this.WhenAnyValue(x => x.UserNameErrorLabel.Text, text => !string.IsNullOrWhiteSpace(text))
|
||||
.BindTo(this, x => x.UserNameErrorLabel.Visibility)
|
||||
.DisposeWith(disposables);
|
||||
this.WhenAnyValue(x => x.PasswordErrorLabel.Text, text => !string.IsNullOrWhiteSpace(text))
|
||||
.BindTo(this, x => x.PasswordErrorLabel.Visibility)
|
||||
.DisposeWith(disposables);
|
||||
this.WhenAnyValue(x => x.FormErrorLabel.Text, text => !string.IsNullOrWhiteSpace(text))
|
||||
.BindTo(this, x => x.FormErrorLabel.Visibility)
|
||||
.DisposeWith(disposables);
|
||||
});
|
||||
}
|
||||
|
||||
public IDirectAuthViewModel ViewModel
|
||||
{
|
||||
get => (IDirectAuthViewModel)GetValue(ViewModelProperty);
|
||||
set => SetValue(ViewModelProperty, value);
|
||||
}
|
||||
public IDirectAuthViewModel ViewModel
|
||||
{
|
||||
get => (IDirectAuthViewModel)GetValue(ViewModelProperty);
|
||||
set => SetValue(ViewModelProperty, value);
|
||||
}
|
||||
|
||||
object IViewFor.ViewModel
|
||||
{
|
||||
get => ViewModel;
|
||||
set => ViewModel = (IDirectAuthViewModel)value;
|
||||
}
|
||||
object IViewFor.ViewModel
|
||||
{
|
||||
get => ViewModel;
|
||||
set => ViewModel = (IDirectAuthViewModel)value;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,45 +8,43 @@ using ReactiveUI;
|
|||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Controls.Primitives;
|
||||
using Windows.UI.Xaml.Input;
|
||||
|
||||
namespace Camelotia.Presentation.Uwp.Views
|
||||
namespace Camelotia.Presentation.Uwp.Views;
|
||||
|
||||
public sealed partial class FileView : UserControl, IViewFor<IFileViewModel>
|
||||
{
|
||||
public sealed partial class FileView : UserControl, IViewFor<IFileViewModel>
|
||||
public static readonly DependencyProperty ViewModelProperty = DependencyProperty
|
||||
.Register(nameof(ViewModel), typeof(IFileViewModel), typeof(FileView), null);
|
||||
|
||||
public FileView()
|
||||
{
|
||||
public static readonly DependencyProperty ViewModelProperty = DependencyProperty
|
||||
.Register(nameof(ViewModel), typeof(IFileViewModel), typeof(FileView), null);
|
||||
|
||||
public FileView()
|
||||
InitializeComponent();
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
InitializeComponent();
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
this.Events()
|
||||
.RightTapped
|
||||
.Select(args => this)
|
||||
.Do(sender => sender.ViewModel.Provider.SelectedFile = sender.ViewModel)
|
||||
.Subscribe(FlyoutBase.ShowAttachedFlyout)
|
||||
.DisposeWith(disposables);
|
||||
this.Events()
|
||||
.RightTapped
|
||||
.Select(args => this)
|
||||
.Do(sender => sender.ViewModel.Provider.SelectedFile = sender.ViewModel)
|
||||
.Subscribe(FlyoutBase.ShowAttachedFlyout)
|
||||
.DisposeWith(disposables);
|
||||
|
||||
this.Events()
|
||||
.DoubleTapped
|
||||
.Select(args => Unit.Default)
|
||||
.InvokeCommand(this, x => x.ViewModel.Provider.Open)
|
||||
.DisposeWith(disposables);
|
||||
});
|
||||
}
|
||||
this.Events()
|
||||
.DoubleTapped
|
||||
.Select(args => Unit.Default)
|
||||
.InvokeCommand(this, x => x.ViewModel.Provider.Open)
|
||||
.DisposeWith(disposables);
|
||||
});
|
||||
}
|
||||
|
||||
public IFileViewModel ViewModel
|
||||
{
|
||||
get => (IFileViewModel)GetValue(ViewModelProperty);
|
||||
set => SetValue(ViewModelProperty, value);
|
||||
}
|
||||
public IFileViewModel ViewModel
|
||||
{
|
||||
get => (IFileViewModel)GetValue(ViewModelProperty);
|
||||
set => SetValue(ViewModelProperty, value);
|
||||
}
|
||||
|
||||
object IViewFor.ViewModel
|
||||
{
|
||||
get => ViewModel;
|
||||
set => ViewModel = (IFileViewModel)value;
|
||||
}
|
||||
object IViewFor.ViewModel
|
||||
{
|
||||
get => ViewModel;
|
||||
set => ViewModel = (IFileViewModel)value;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,57 +7,56 @@ using ReactiveUI.Validation.Formatters;
|
|||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
|
||||
namespace Camelotia.Presentation.Uwp.Views
|
||||
namespace Camelotia.Presentation.Uwp.Views;
|
||||
|
||||
public sealed partial class HostAuthView : UserControl, IViewFor<IHostAuthViewModel>
|
||||
{
|
||||
public sealed partial class HostAuthView : UserControl, IViewFor<IHostAuthViewModel>
|
||||
public static readonly DependencyProperty ViewModelProperty = DependencyProperty
|
||||
.Register(nameof(ViewModel), typeof(IHostAuthViewModel), typeof(DirectAuthView), null);
|
||||
|
||||
public HostAuthView()
|
||||
{
|
||||
public static readonly DependencyProperty ViewModelProperty = DependencyProperty
|
||||
.Register(nameof(ViewModel), typeof(IHostAuthViewModel), typeof(DirectAuthView), null);
|
||||
|
||||
public HostAuthView()
|
||||
InitializeComponent();
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
InitializeComponent();
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
this.BindValidation(ViewModel, x => x.Address, x => x.HostNameErrorLabel.Text)
|
||||
.DisposeWith(disposables);
|
||||
this.BindValidation(ViewModel, x => x.Port, x => x.PortErrorLabel.Text)
|
||||
.DisposeWith(disposables);
|
||||
this.BindValidation(ViewModel, x => x.Username, x => x.UserNameErrorLabel.Text)
|
||||
.DisposeWith(disposables);
|
||||
this.BindValidation(ViewModel, x => x.Password, x => x.PasswordErrorLabel.Text)
|
||||
.DisposeWith(disposables);
|
||||
this.BindValidation(ViewModel, x => x.FormErrorLabel.Text, new SingleLineFormatter(Environment.NewLine))
|
||||
.DisposeWith(disposables);
|
||||
this.BindValidation(ViewModel, x => x.Address, x => x.HostNameErrorLabel.Text)
|
||||
.DisposeWith(disposables);
|
||||
this.BindValidation(ViewModel, x => x.Port, x => x.PortErrorLabel.Text)
|
||||
.DisposeWith(disposables);
|
||||
this.BindValidation(ViewModel, x => x.Username, x => x.UserNameErrorLabel.Text)
|
||||
.DisposeWith(disposables);
|
||||
this.BindValidation(ViewModel, x => x.Password, x => x.PasswordErrorLabel.Text)
|
||||
.DisposeWith(disposables);
|
||||
this.BindValidation(ViewModel, x => x.FormErrorLabel.Text, new SingleLineFormatter(Environment.NewLine))
|
||||
.DisposeWith(disposables);
|
||||
|
||||
this.WhenAnyValue(x => x.HostNameErrorLabel.Text, text => !string.IsNullOrWhiteSpace(text))
|
||||
.BindTo(this, x => x.HostNameErrorLabel.Visibility)
|
||||
.DisposeWith(disposables);
|
||||
this.WhenAnyValue(x => x.PortErrorLabel.Text, text => !string.IsNullOrWhiteSpace(text))
|
||||
.BindTo(this, x => x.PortErrorLabel.Visibility)
|
||||
.DisposeWith(disposables);
|
||||
this.WhenAnyValue(x => x.UserNameErrorLabel.Text, text => !string.IsNullOrWhiteSpace(text))
|
||||
.BindTo(this, x => x.UserNameErrorLabel.Visibility)
|
||||
.DisposeWith(disposables);
|
||||
this.WhenAnyValue(x => x.PasswordErrorLabel.Text, text => !string.IsNullOrWhiteSpace(text))
|
||||
.BindTo(this, x => x.PasswordErrorLabel.Visibility)
|
||||
.DisposeWith(disposables);
|
||||
this.WhenAnyValue(x => x.FormErrorLabel.Text, text => !string.IsNullOrWhiteSpace(text))
|
||||
.BindTo(this, x => x.FormErrorLabel.Visibility)
|
||||
.DisposeWith(disposables);
|
||||
});
|
||||
}
|
||||
this.WhenAnyValue(x => x.HostNameErrorLabel.Text, text => !string.IsNullOrWhiteSpace(text))
|
||||
.BindTo(this, x => x.HostNameErrorLabel.Visibility)
|
||||
.DisposeWith(disposables);
|
||||
this.WhenAnyValue(x => x.PortErrorLabel.Text, text => !string.IsNullOrWhiteSpace(text))
|
||||
.BindTo(this, x => x.PortErrorLabel.Visibility)
|
||||
.DisposeWith(disposables);
|
||||
this.WhenAnyValue(x => x.UserNameErrorLabel.Text, text => !string.IsNullOrWhiteSpace(text))
|
||||
.BindTo(this, x => x.UserNameErrorLabel.Visibility)
|
||||
.DisposeWith(disposables);
|
||||
this.WhenAnyValue(x => x.PasswordErrorLabel.Text, text => !string.IsNullOrWhiteSpace(text))
|
||||
.BindTo(this, x => x.PasswordErrorLabel.Visibility)
|
||||
.DisposeWith(disposables);
|
||||
this.WhenAnyValue(x => x.FormErrorLabel.Text, text => !string.IsNullOrWhiteSpace(text))
|
||||
.BindTo(this, x => x.FormErrorLabel.Visibility)
|
||||
.DisposeWith(disposables);
|
||||
});
|
||||
}
|
||||
|
||||
public IHostAuthViewModel ViewModel
|
||||
{
|
||||
get => (IHostAuthViewModel)GetValue(ViewModelProperty);
|
||||
set => SetValue(ViewModelProperty, value);
|
||||
}
|
||||
public IHostAuthViewModel ViewModel
|
||||
{
|
||||
get => (IHostAuthViewModel)GetValue(ViewModelProperty);
|
||||
set => SetValue(ViewModelProperty, value);
|
||||
}
|
||||
|
||||
object IViewFor.ViewModel
|
||||
{
|
||||
get => ViewModel;
|
||||
set => ViewModel = (IHostAuthViewModel)value;
|
||||
}
|
||||
object IViewFor.ViewModel
|
||||
{
|
||||
get => ViewModel;
|
||||
set => ViewModel = (IHostAuthViewModel)value;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,29 +3,28 @@ using ReactiveUI;
|
|||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
|
||||
namespace Camelotia.Presentation.Uwp.Views
|
||||
namespace Camelotia.Presentation.Uwp.Views;
|
||||
|
||||
public sealed partial class OAuthView : UserControl, IViewFor<IOAuthViewModel>
|
||||
{
|
||||
public sealed partial class OAuthView : UserControl, IViewFor<IOAuthViewModel>
|
||||
public static readonly DependencyProperty ViewModelProperty = DependencyProperty
|
||||
.Register(nameof(ViewModel), typeof(IOAuthViewModel), typeof(OAuthView), null);
|
||||
|
||||
public OAuthView()
|
||||
{
|
||||
public static readonly DependencyProperty ViewModelProperty = DependencyProperty
|
||||
.Register(nameof(ViewModel), typeof(IOAuthViewModel), typeof(OAuthView), null);
|
||||
InitializeComponent();
|
||||
this.WhenActivated(disposables => { });
|
||||
}
|
||||
|
||||
public OAuthView()
|
||||
{
|
||||
InitializeComponent();
|
||||
this.WhenActivated(disposables => { });
|
||||
}
|
||||
public IOAuthViewModel ViewModel
|
||||
{
|
||||
get => (IOAuthViewModel)GetValue(ViewModelProperty);
|
||||
set => SetValue(ViewModelProperty, value);
|
||||
}
|
||||
|
||||
public IOAuthViewModel ViewModel
|
||||
{
|
||||
get => (IOAuthViewModel)GetValue(ViewModelProperty);
|
||||
set => SetValue(ViewModelProperty, value);
|
||||
}
|
||||
|
||||
object IViewFor.ViewModel
|
||||
{
|
||||
get => ViewModel;
|
||||
set => ViewModel = (IOAuthViewModel)value;
|
||||
}
|
||||
object IViewFor.ViewModel
|
||||
{
|
||||
get => ViewModel;
|
||||
set => ViewModel = (IOAuthViewModel)value;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,42 +7,41 @@ using ReactiveUI.Validation.Formatters;
|
|||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
|
||||
namespace Camelotia.Presentation.Uwp.Views
|
||||
namespace Camelotia.Presentation.Uwp.Views;
|
||||
|
||||
public sealed partial class RenameFileView : UserControl, IViewFor<IRenameFileViewModel>
|
||||
{
|
||||
public sealed partial class RenameFileView : UserControl, IViewFor<IRenameFileViewModel>
|
||||
public static readonly DependencyProperty ViewModelProperty = DependencyProperty
|
||||
.Register(nameof(ViewModel), typeof(IRenameFileViewModel), typeof(RenameFileView), null);
|
||||
|
||||
public RenameFileView()
|
||||
{
|
||||
public static readonly DependencyProperty ViewModelProperty = DependencyProperty
|
||||
.Register(nameof(ViewModel), typeof(IRenameFileViewModel), typeof(RenameFileView), null);
|
||||
|
||||
public RenameFileView()
|
||||
InitializeComponent();
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
InitializeComponent();
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
this.BindValidation(ViewModel, x => x.NewName, x => x.FileNameErrorLabel.Text)
|
||||
.DisposeWith(disposables);
|
||||
this.BindValidation(ViewModel, x => x.FormErrorLabel.Text, new SingleLineFormatter(Environment.NewLine))
|
||||
.DisposeWith(disposables);
|
||||
this.BindValidation(ViewModel, x => x.NewName, x => x.FileNameErrorLabel.Text)
|
||||
.DisposeWith(disposables);
|
||||
this.BindValidation(ViewModel, x => x.FormErrorLabel.Text, new SingleLineFormatter(Environment.NewLine))
|
||||
.DisposeWith(disposables);
|
||||
|
||||
this.WhenAnyValue(x => x.FileNameErrorLabel.Text, text => !string.IsNullOrWhiteSpace(text))
|
||||
.BindTo(this, x => x.FileNameErrorLabel.Visibility)
|
||||
.DisposeWith(disposables);
|
||||
this.WhenAnyValue(x => x.FormErrorLabel.Text, text => !string.IsNullOrWhiteSpace(text))
|
||||
.BindTo(this, x => x.FormErrorLabel.Visibility)
|
||||
.DisposeWith(disposables);
|
||||
});
|
||||
}
|
||||
this.WhenAnyValue(x => x.FileNameErrorLabel.Text, text => !string.IsNullOrWhiteSpace(text))
|
||||
.BindTo(this, x => x.FileNameErrorLabel.Visibility)
|
||||
.DisposeWith(disposables);
|
||||
this.WhenAnyValue(x => x.FormErrorLabel.Text, text => !string.IsNullOrWhiteSpace(text))
|
||||
.BindTo(this, x => x.FormErrorLabel.Visibility)
|
||||
.DisposeWith(disposables);
|
||||
});
|
||||
}
|
||||
|
||||
public IRenameFileViewModel ViewModel
|
||||
{
|
||||
get => (IRenameFileViewModel)GetValue(ViewModelProperty);
|
||||
set => SetValue(ViewModelProperty, value);
|
||||
}
|
||||
public IRenameFileViewModel ViewModel
|
||||
{
|
||||
get => (IRenameFileViewModel)GetValue(ViewModelProperty);
|
||||
set => SetValue(ViewModelProperty, value);
|
||||
}
|
||||
|
||||
object IViewFor.ViewModel
|
||||
{
|
||||
get => ViewModel;
|
||||
set => ViewModel = (IRenameFileViewModel)value;
|
||||
}
|
||||
object IViewFor.ViewModel
|
||||
{
|
||||
get => ViewModel;
|
||||
set => ViewModel = (IRenameFileViewModel)value;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,48 +6,47 @@ using Camelotia.Presentation.Wpf.Services;
|
|||
using Camelotia.Services;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace Camelotia.Presentation.Wpf
|
||||
namespace Camelotia.Presentation.Wpf;
|
||||
|
||||
public partial class App : Application
|
||||
{
|
||||
public partial class App : Application
|
||||
private readonly AutoSuspendHelper _autoSuspendHelper;
|
||||
|
||||
public App()
|
||||
{
|
||||
private readonly AutoSuspendHelper _autoSuspendHelper;
|
||||
InitializeComponent();
|
||||
_autoSuspendHelper = new AutoSuspendHelper(this);
|
||||
RxApp.SuspensionHost.CreateNewAppState = () => new MainState();
|
||||
RxApp.SuspensionHost.SetupDefaultSuspendResume(new NewtonsoftJsonSuspensionDriver("appstate.json"));
|
||||
}
|
||||
|
||||
public App()
|
||||
{
|
||||
InitializeComponent();
|
||||
_autoSuspendHelper = new AutoSuspendHelper(this);
|
||||
RxApp.SuspensionHost.CreateNewAppState = () => new MainState();
|
||||
RxApp.SuspensionHost.SetupDefaultSuspendResume(new NewtonsoftJsonSuspensionDriver("appstate.json"));
|
||||
}
|
||||
protected override void OnStartup(StartupEventArgs e)
|
||||
{
|
||||
base.OnStartup(e);
|
||||
Akavache.BlobCache.ApplicationName = "Camelotia";
|
||||
var mainState = RxApp.SuspensionHost.GetAppState<MainState>();
|
||||
var mainViewModel = new MainViewModel(
|
||||
mainState,
|
||||
new CloudFactory(
|
||||
mainState.CloudConfiguration,
|
||||
new WindowsPresentationYandexAuthenticator(),
|
||||
Akavache.BlobCache.UserAccount),
|
||||
(state, provider) => new CloudViewModel(
|
||||
state,
|
||||
owner => new CreateFolderViewModel(state.CreateFolderState, owner, provider),
|
||||
owner => new RenameFileViewModel(state.RenameFileState, owner, provider),
|
||||
(file, owner) => new FileViewModel(owner, file),
|
||||
(folder, owner) => new FolderViewModel(owner, folder),
|
||||
new AuthViewModel(
|
||||
new DirectAuthViewModel(state.AuthState.DirectAuthState, provider),
|
||||
new HostAuthViewModel(state.AuthState.HostAuthState, provider),
|
||||
new OAuthViewModel(provider),
|
||||
provider),
|
||||
new WindowsPresentationFileManager(),
|
||||
provider));
|
||||
|
||||
protected override void OnStartup(StartupEventArgs e)
|
||||
{
|
||||
base.OnStartup(e);
|
||||
Akavache.BlobCache.ApplicationName = "Camelotia";
|
||||
var mainState = RxApp.SuspensionHost.GetAppState<MainState>();
|
||||
var mainViewModel = new MainViewModel(
|
||||
mainState,
|
||||
new CloudFactory(
|
||||
mainState.CloudConfiguration,
|
||||
new WindowsPresentationYandexAuthenticator(),
|
||||
Akavache.BlobCache.UserAccount),
|
||||
(state, provider) => new CloudViewModel(
|
||||
state,
|
||||
owner => new CreateFolderViewModel(state.CreateFolderState, owner, provider),
|
||||
owner => new RenameFileViewModel(state.RenameFileState, owner, provider),
|
||||
(file, owner) => new FileViewModel(owner, file),
|
||||
(folder, owner) => new FolderViewModel(owner, folder),
|
||||
new AuthViewModel(
|
||||
new DirectAuthViewModel(state.AuthState.DirectAuthState, provider),
|
||||
new HostAuthViewModel(state.AuthState.HostAuthState, provider),
|
||||
new OAuthViewModel(provider),
|
||||
provider),
|
||||
new WindowsPresentationFileManager(),
|
||||
provider));
|
||||
|
||||
var window = new MainView { DataContext = mainViewModel };
|
||||
window.Closed += (sender, e) => Shutdown();
|
||||
window.Show();
|
||||
}
|
||||
var window = new MainView { DataContext = mainViewModel };
|
||||
window.Closed += (sender, e) => Shutdown();
|
||||
window.Show();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,9 +2,11 @@
|
|||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<StartupObject>Camelotia.Presentation.Wpf.Program</StartupObject>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<TargetFramework>net6-windows</TargetFramework>
|
||||
<IncludePackageReferencesDuringMarkupCompilation>true</IncludePackageReferencesDuringMarkupCompilation>
|
||||
<UseWpf>true</UseWpf>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<LangVersion>latest</LangVersion>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="akavache" Version="7.3.1" />
|
||||
|
|
|
@ -6,46 +6,45 @@ using System.Windows.Controls;
|
|||
using Camelotia.Presentation.Interfaces;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace Camelotia.Presentation.Wpf.Views
|
||||
namespace Camelotia.Presentation.Wpf.Views;
|
||||
|
||||
public partial class AuthView : UserControl, IViewFor<IAuthViewModel>
|
||||
{
|
||||
public partial class AuthView : UserControl, IViewFor<IAuthViewModel>
|
||||
public static readonly DependencyProperty ViewModelProperty = DependencyProperty
|
||||
.Register(nameof(ViewModel), typeof(IAuthViewModel), typeof(AuthView), null);
|
||||
|
||||
public AuthView()
|
||||
{
|
||||
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 =>
|
||||
{
|
||||
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.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.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);
|
||||
});
|
||||
}
|
||||
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);
|
||||
}
|
||||
public IAuthViewModel ViewModel
|
||||
{
|
||||
get => (IAuthViewModel)GetValue(ViewModelProperty);
|
||||
set => SetValue(ViewModelProperty, value);
|
||||
}
|
||||
|
||||
object IViewFor.ViewModel
|
||||
{
|
||||
get => ViewModel;
|
||||
set => ViewModel = (IAuthViewModel)value;
|
||||
}
|
||||
object IViewFor.ViewModel
|
||||
{
|
||||
get => ViewModel;
|
||||
set => ViewModel = (IAuthViewModel)value;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,45 +4,44 @@ using System.Windows.Controls;
|
|||
using Camelotia.Presentation.Interfaces;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace Camelotia.Presentation.Wpf.Views
|
||||
{
|
||||
public partial class CloudView : UserControl, IViewFor<ICloudViewModel>
|
||||
{
|
||||
public static readonly DependencyProperty ViewModelProperty = DependencyProperty
|
||||
.Register(nameof(ViewModel), typeof(ICloudViewModel), typeof(CloudView), null);
|
||||
namespace Camelotia.Presentation.Wpf.Views;
|
||||
|
||||
public CloudView()
|
||||
public partial class CloudView : UserControl, IViewFor<ICloudViewModel>
|
||||
{
|
||||
public static readonly DependencyProperty ViewModelProperty = DependencyProperty
|
||||
.Register(nameof(ViewModel), typeof(ICloudViewModel), typeof(CloudView), null);
|
||||
|
||||
public CloudView()
|
||||
{
|
||||
InitializeComponent();
|
||||
DataContextChanged += (sender, args) => ViewModel = DataContext as ICloudViewModel;
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
InitializeComponent();
|
||||
DataContextChanged += (sender, args) => ViewModel = DataContext as ICloudViewModel;
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
this.OneWayBind(
|
||||
this.OneWayBind(
|
||||
ViewModel,
|
||||
vm => vm.ShowBreadCrumbs,
|
||||
view => view.PathTextBlock.Visibility,
|
||||
showBreadCrumbs => showBreadCrumbs ? Visibility.Collapsed : Visibility.Visible)
|
||||
.DisposeWith(disposables);
|
||||
.DisposeWith(disposables);
|
||||
|
||||
this.OneWayBind(
|
||||
this.OneWayBind(
|
||||
ViewModel,
|
||||
vm => vm.ShowBreadCrumbs,
|
||||
view => view.BreadCrumbsListBox.Visibility,
|
||||
showBreadCrumbs => showBreadCrumbs ? Visibility.Visible : Visibility.Collapsed)
|
||||
.DisposeWith(disposables);
|
||||
});
|
||||
}
|
||||
.DisposeWith(disposables);
|
||||
});
|
||||
}
|
||||
|
||||
public ICloudViewModel ViewModel
|
||||
{
|
||||
get => (ICloudViewModel)GetValue(ViewModelProperty);
|
||||
set => SetValue(ViewModelProperty, value);
|
||||
}
|
||||
public ICloudViewModel ViewModel
|
||||
{
|
||||
get => (ICloudViewModel)GetValue(ViewModelProperty);
|
||||
set => SetValue(ViewModelProperty, value);
|
||||
}
|
||||
|
||||
object IViewFor.ViewModel
|
||||
{
|
||||
get => ViewModel;
|
||||
set => ViewModel = (ICloudViewModel)value;
|
||||
}
|
||||
object IViewFor.ViewModel
|
||||
{
|
||||
get => ViewModel;
|
||||
set => ViewModel = (ICloudViewModel)value;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,30 +3,29 @@ using System.Windows.Controls;
|
|||
using Camelotia.Presentation.Interfaces;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace Camelotia.Presentation.Wpf.Views
|
||||
namespace Camelotia.Presentation.Wpf.Views;
|
||||
|
||||
public partial class CreateFolderView : UserControl, IViewFor<ICreateFolderViewModel>
|
||||
{
|
||||
public partial class CreateFolderView : UserControl, IViewFor<ICreateFolderViewModel>
|
||||
public static readonly DependencyProperty ViewModelProperty = DependencyProperty
|
||||
.Register(nameof(ViewModel), typeof(ICreateFolderViewModel), typeof(CreateFolderView), null);
|
||||
|
||||
public CreateFolderView()
|
||||
{
|
||||
public static readonly DependencyProperty ViewModelProperty = DependencyProperty
|
||||
.Register(nameof(ViewModel), typeof(ICreateFolderViewModel), typeof(CreateFolderView), null);
|
||||
InitializeComponent();
|
||||
DataContextChanged += (sender, args) => ViewModel = DataContext as ICreateFolderViewModel;
|
||||
this.WhenActivated(disposable => { });
|
||||
}
|
||||
|
||||
public CreateFolderView()
|
||||
{
|
||||
InitializeComponent();
|
||||
DataContextChanged += (sender, args) => ViewModel = DataContext as ICreateFolderViewModel;
|
||||
this.WhenActivated(disposable => { });
|
||||
}
|
||||
public ICreateFolderViewModel ViewModel
|
||||
{
|
||||
get => (ICreateFolderViewModel)GetValue(ViewModelProperty);
|
||||
set => SetValue(ViewModelProperty, value);
|
||||
}
|
||||
|
||||
public ICreateFolderViewModel ViewModel
|
||||
{
|
||||
get => (ICreateFolderViewModel)GetValue(ViewModelProperty);
|
||||
set => SetValue(ViewModelProperty, value);
|
||||
}
|
||||
|
||||
object IViewFor.ViewModel
|
||||
{
|
||||
get => ViewModel;
|
||||
set => ViewModel = (ICreateFolderViewModel)value;
|
||||
}
|
||||
object IViewFor.ViewModel
|
||||
{
|
||||
get => ViewModel;
|
||||
set => ViewModel = (ICreateFolderViewModel)value;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,30 +3,29 @@ using System.Windows.Controls;
|
|||
using Camelotia.Presentation.Interfaces;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace Camelotia.Presentation.Wpf.Views
|
||||
namespace Camelotia.Presentation.Wpf.Views;
|
||||
|
||||
public partial class DirectAuthView : UserControl, IViewFor<IDirectAuthViewModel>
|
||||
{
|
||||
public partial class DirectAuthView : UserControl, IViewFor<IDirectAuthViewModel>
|
||||
public static readonly DependencyProperty ViewModelProperty = DependencyProperty
|
||||
.Register(nameof(ViewModel), typeof(IDirectAuthViewModel), typeof(DirectAuthView), null);
|
||||
|
||||
public DirectAuthView()
|
||||
{
|
||||
public static readonly DependencyProperty ViewModelProperty = DependencyProperty
|
||||
.Register(nameof(ViewModel), typeof(IDirectAuthViewModel), typeof(DirectAuthView), null);
|
||||
InitializeComponent();
|
||||
DataContextChanged += (sender, args) => ViewModel = DataContext as IDirectAuthViewModel;
|
||||
this.WhenActivated(disposable => { });
|
||||
}
|
||||
|
||||
public DirectAuthView()
|
||||
{
|
||||
InitializeComponent();
|
||||
DataContextChanged += (sender, args) => ViewModel = DataContext as IDirectAuthViewModel;
|
||||
this.WhenActivated(disposable => { });
|
||||
}
|
||||
public IDirectAuthViewModel ViewModel
|
||||
{
|
||||
get => (IDirectAuthViewModel)GetValue(ViewModelProperty);
|
||||
set => SetValue(ViewModelProperty, value);
|
||||
}
|
||||
|
||||
public IDirectAuthViewModel ViewModel
|
||||
{
|
||||
get => (IDirectAuthViewModel)GetValue(ViewModelProperty);
|
||||
set => SetValue(ViewModelProperty, value);
|
||||
}
|
||||
|
||||
object IViewFor.ViewModel
|
||||
{
|
||||
get => ViewModel;
|
||||
set => ViewModel = (IDirectAuthViewModel)value;
|
||||
}
|
||||
object IViewFor.ViewModel
|
||||
{
|
||||
get => ViewModel;
|
||||
set => ViewModel = (IDirectAuthViewModel)value;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ namespace Camelotia.Presentation.Xamarin.Droid
|
|||
{
|
||||
|
||||
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Xamarin.Android.Build.Tasks", "1.0.0.0")]
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Xamarin.Android.Build.Tasks", "12.1.0.11")]
|
||||
public partial class Resource
|
||||
{
|
||||
|
||||
|
|
|
@ -6,19 +6,18 @@ using Xamarin.Forms.Xaml;
|
|||
|
||||
[assembly: XamlCompilation(XamlCompilationOptions.Compile)]
|
||||
|
||||
namespace Camelotia.Presentation.Xamarin
|
||||
{
|
||||
public partial class App : Application
|
||||
{
|
||||
public App(IMainViewModel viewModel)
|
||||
{
|
||||
Plugin.Iconize.Iconize
|
||||
.With(new FontAwesomeRegularModule())
|
||||
.With(new FontAwesomeSolidModule())
|
||||
.With(new FontAwesomeBrandsModule());
|
||||
namespace Camelotia.Presentation.Xamarin;
|
||||
|
||||
InitializeComponent();
|
||||
MainPage = new MainView { ViewModel = viewModel };
|
||||
}
|
||||
public partial class App : Application
|
||||
{
|
||||
public App(IMainViewModel viewModel)
|
||||
{
|
||||
Plugin.Iconize.Iconize
|
||||
.With(new FontAwesomeRegularModule())
|
||||
.With(new FontAwesomeSolidModule())
|
||||
.With(new FontAwesomeBrandsModule());
|
||||
|
||||
InitializeComponent();
|
||||
MainPage = new MainView { ViewModel = viewModel };
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<LangVersion>latest</LangVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
using Xamarin.Forms;
|
||||
|
||||
namespace Camelotia.Presentation.Xamarin.Controls
|
||||
namespace Camelotia.Presentation.Xamarin.Controls;
|
||||
|
||||
public class AccentButton : Button
|
||||
{
|
||||
public class AccentButton : Button
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,37 +6,36 @@ using ReactiveUI;
|
|||
using ReactiveUI.XamForms;
|
||||
using Xamarin.Forms.Xaml;
|
||||
|
||||
namespace Camelotia.Presentation.Xamarin.Views
|
||||
namespace Camelotia.Presentation.Xamarin.Views;
|
||||
|
||||
[XamlCompilation(XamlCompilationOptions.Compile)]
|
||||
public partial class AuthView : ReactiveTabbedPage<IAuthViewModel>
|
||||
{
|
||||
[XamlCompilation(XamlCompilationOptions.Compile)]
|
||||
public partial class AuthView : ReactiveTabbedPage<IAuthViewModel>
|
||||
public AuthView()
|
||||
{
|
||||
public AuthView()
|
||||
InitializeComponent();
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
InitializeComponent();
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
this.WhenAnyValue(x => x.ViewModel.SupportsDirectAuth)
|
||||
.Where(supportsDirectAuth => supportsDirectAuth)
|
||||
.Select(supports => new DirectAuthView { ViewModel = ViewModel.DirectAuth })
|
||||
.Do(view => Children.Clear())
|
||||
.Subscribe(view => Children.Add(view))
|
||||
.DisposeWith(disposables);
|
||||
this.WhenAnyValue(x => x.ViewModel.SupportsDirectAuth)
|
||||
.Where(supportsDirectAuth => supportsDirectAuth)
|
||||
.Select(supports => new DirectAuthView { ViewModel = ViewModel.DirectAuth })
|
||||
.Do(view => Children.Clear())
|
||||
.Subscribe(view => Children.Add(view))
|
||||
.DisposeWith(disposables);
|
||||
|
||||
this.WhenAnyValue(x => x.ViewModel.SupportsOAuth)
|
||||
.Where(supportsOAuth => supportsOAuth)
|
||||
.Select(supports => new OAuthView { ViewModel = ViewModel.OAuth })
|
||||
.Do(view => Children.Clear())
|
||||
.Subscribe(view => Children.Add(view))
|
||||
.DisposeWith(disposables);
|
||||
this.WhenAnyValue(x => x.ViewModel.SupportsOAuth)
|
||||
.Where(supportsOAuth => supportsOAuth)
|
||||
.Select(supports => new OAuthView { ViewModel = ViewModel.OAuth })
|
||||
.Do(view => Children.Clear())
|
||||
.Subscribe(view => Children.Add(view))
|
||||
.DisposeWith(disposables);
|
||||
|
||||
this.WhenAnyValue(x => x.ViewModel.SupportsHostAuth)
|
||||
.Where(supportsHostAuth => supportsHostAuth)
|
||||
.Select(supports => new HostAuthView { ViewModel = ViewModel.HostAuth })
|
||||
.Do(view => Children.Clear())
|
||||
.Subscribe(view => Children.Add(view))
|
||||
.DisposeWith(disposables);
|
||||
});
|
||||
}
|
||||
this.WhenAnyValue(x => x.ViewModel.SupportsHostAuth)
|
||||
.Where(supportsHostAuth => supportsHostAuth)
|
||||
.Select(supports => new HostAuthView { ViewModel = ViewModel.HostAuth })
|
||||
.Do(view => Children.Clear())
|
||||
.Subscribe(view => Children.Add(view))
|
||||
.DisposeWith(disposables);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,26 +6,25 @@ using ReactiveUI.XamForms;
|
|||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Xaml;
|
||||
|
||||
namespace Camelotia.Presentation.Xamarin.Views
|
||||
{
|
||||
[XamlCompilation(XamlCompilationOptions.Compile)]
|
||||
public partial class CloudExplorerFileView : ReactiveViewCell<IFileViewModel>
|
||||
{
|
||||
public CloudExplorerFileView()
|
||||
{
|
||||
InitializeComponent();
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
this.WhenAnyValue(x => x.ViewModel.IsFolder)
|
||||
.Select(folder => folder ? "fas-folder" : "fas-file")
|
||||
.BindTo(this, x => x.IconImage.Icon)
|
||||
.DisposeWith(disposables);
|
||||
namespace Camelotia.Presentation.Xamarin.Views;
|
||||
|
||||
this.WhenAnyValue(x => x.ViewModel.IsFile)
|
||||
.Select(file => file ? Color.FromRgb(130, 113, 209) : Color.FromRgb(100, 83, 179))
|
||||
.BindTo(this, x => x.IconImage.IconColor)
|
||||
.DisposeWith(disposables);
|
||||
});
|
||||
}
|
||||
[XamlCompilation(XamlCompilationOptions.Compile)]
|
||||
public partial class CloudExplorerFileView : ReactiveViewCell<IFileViewModel>
|
||||
{
|
||||
public CloudExplorerFileView()
|
||||
{
|
||||
InitializeComponent();
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
this.WhenAnyValue(x => x.ViewModel.IsFolder)
|
||||
.Select(folder => folder ? "fas-folder" : "fas-file")
|
||||
.BindTo(this, x => x.IconImage.Icon)
|
||||
.DisposeWith(disposables);
|
||||
|
||||
this.WhenAnyValue(x => x.ViewModel.IsFile)
|
||||
.Select(file => file ? Color.FromRgb(130, 113, 209) : Color.FromRgb(100, 83, 179))
|
||||
.BindTo(this, x => x.IconImage.IconColor)
|
||||
.DisposeWith(disposables);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,19 +4,18 @@ using ReactiveUI;
|
|||
using ReactiveUI.XamForms;
|
||||
using Xamarin.Forms.Xaml;
|
||||
|
||||
namespace Camelotia.Presentation.Xamarin.Views
|
||||
namespace Camelotia.Presentation.Xamarin.Views;
|
||||
|
||||
[XamlCompilation(XamlCompilationOptions.Compile)]
|
||||
public partial class CloudExplorerView : ReactiveContentPage<ICloudViewModel>
|
||||
{
|
||||
[XamlCompilation(XamlCompilationOptions.Compile)]
|
||||
public partial class CloudExplorerView : ReactiveContentPage<ICloudViewModel>
|
||||
public CloudExplorerView()
|
||||
{
|
||||
public CloudExplorerView()
|
||||
InitializeComponent();
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
InitializeComponent();
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
this.OneWayBind(ViewModel, x => x.IsLoading, x => x.FilesListView.IsRefreshing)
|
||||
.DisposeWith(disposables);
|
||||
});
|
||||
}
|
||||
this.OneWayBind(ViewModel, x => x.IsLoading, x => x.FilesListView.IsRefreshing)
|
||||
.DisposeWith(disposables);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,28 +7,27 @@ using ReactiveUI.Validation.Formatters;
|
|||
using ReactiveUI.XamForms;
|
||||
using Xamarin.Forms.Xaml;
|
||||
|
||||
namespace Camelotia.Presentation.Xamarin.Views
|
||||
{
|
||||
[XamlCompilation(XamlCompilationOptions.Compile)]
|
||||
public partial class CreateFolderView : ReactiveContentPage<ICreateFolderViewModel>
|
||||
{
|
||||
public CreateFolderView()
|
||||
{
|
||||
InitializeComponent();
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
this.BindValidation(ViewModel, x => x.Name, x => x.FolderNameErrorLabel.Text)
|
||||
.DisposeWith(disposables);
|
||||
this.BindValidation(ViewModel, x => x.FormErrorLabel.Text, new SingleLineFormatter(Environment.NewLine))
|
||||
.DisposeWith(disposables);
|
||||
namespace Camelotia.Presentation.Xamarin.Views;
|
||||
|
||||
this.WhenAnyValue(x => x.FolderNameErrorLabel.Text, text => !string.IsNullOrWhiteSpace(text))
|
||||
.BindTo(this, x => x.FolderNameErrorLabel.IsVisible)
|
||||
.DisposeWith(disposables);
|
||||
this.WhenAnyValue(x => x.FormErrorLabel.Text, text => !string.IsNullOrWhiteSpace(text))
|
||||
.BindTo(this, x => x.FormErrorLabel.IsVisible)
|
||||
.DisposeWith(disposables);
|
||||
});
|
||||
}
|
||||
[XamlCompilation(XamlCompilationOptions.Compile)]
|
||||
public partial class CreateFolderView : ReactiveContentPage<ICreateFolderViewModel>
|
||||
{
|
||||
public CreateFolderView()
|
||||
{
|
||||
InitializeComponent();
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
this.BindValidation(ViewModel, x => x.Name, x => x.FolderNameErrorLabel.Text)
|
||||
.DisposeWith(disposables);
|
||||
this.BindValidation(ViewModel, x => x.FormErrorLabel.Text, new SingleLineFormatter(Environment.NewLine))
|
||||
.DisposeWith(disposables);
|
||||
|
||||
this.WhenAnyValue(x => x.FolderNameErrorLabel.Text, text => !string.IsNullOrWhiteSpace(text))
|
||||
.BindTo(this, x => x.FolderNameErrorLabel.IsVisible)
|
||||
.DisposeWith(disposables);
|
||||
this.WhenAnyValue(x => x.FormErrorLabel.Text, text => !string.IsNullOrWhiteSpace(text))
|
||||
.BindTo(this, x => x.FormErrorLabel.IsVisible)
|
||||
.DisposeWith(disposables);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,33 +7,32 @@ using ReactiveUI.Validation.Formatters;
|
|||
using ReactiveUI.XamForms;
|
||||
using Xamarin.Forms.Xaml;
|
||||
|
||||
namespace Camelotia.Presentation.Xamarin.Views
|
||||
{
|
||||
[XamlCompilation(XamlCompilationOptions.Compile)]
|
||||
public partial class DirectAuthView : ReactiveContentPage<IDirectAuthViewModel>
|
||||
{
|
||||
public DirectAuthView()
|
||||
{
|
||||
InitializeComponent();
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
this.BindValidation(ViewModel, x => x.Username, x => x.UserNameErrorLabel.Text)
|
||||
.DisposeWith(disposables);
|
||||
this.BindValidation(ViewModel, x => x.Password, x => x.PasswordErrorLabel.Text)
|
||||
.DisposeWith(disposables);
|
||||
this.BindValidation(ViewModel, x => x.FormErrorLabel.Text, new SingleLineFormatter(Environment.NewLine))
|
||||
.DisposeWith(disposables);
|
||||
namespace Camelotia.Presentation.Xamarin.Views;
|
||||
|
||||
this.WhenAnyValue(x => x.UserNameErrorLabel.Text, text => !string.IsNullOrWhiteSpace(text))
|
||||
.BindTo(this, x => x.UserNameErrorLabel.IsVisible)
|
||||
.DisposeWith(disposables);
|
||||
this.WhenAnyValue(x => x.PasswordErrorLabel.Text, text => !string.IsNullOrWhiteSpace(text))
|
||||
.BindTo(this, x => x.PasswordErrorLabel.IsVisible)
|
||||
.DisposeWith(disposables);
|
||||
this.WhenAnyValue(x => x.FormErrorLabel.Text, text => !string.IsNullOrWhiteSpace(text))
|
||||
.BindTo(this, x => x.FormErrorLabel.IsVisible)
|
||||
.DisposeWith(disposables);
|
||||
});
|
||||
}
|
||||
[XamlCompilation(XamlCompilationOptions.Compile)]
|
||||
public partial class DirectAuthView : ReactiveContentPage<IDirectAuthViewModel>
|
||||
{
|
||||
public DirectAuthView()
|
||||
{
|
||||
InitializeComponent();
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
this.BindValidation(ViewModel, x => x.Username, x => x.UserNameErrorLabel.Text)
|
||||
.DisposeWith(disposables);
|
||||
this.BindValidation(ViewModel, x => x.Password, x => x.PasswordErrorLabel.Text)
|
||||
.DisposeWith(disposables);
|
||||
this.BindValidation(ViewModel, x => x.FormErrorLabel.Text, new SingleLineFormatter(Environment.NewLine))
|
||||
.DisposeWith(disposables);
|
||||
|
||||
this.WhenAnyValue(x => x.UserNameErrorLabel.Text, text => !string.IsNullOrWhiteSpace(text))
|
||||
.BindTo(this, x => x.UserNameErrorLabel.IsVisible)
|
||||
.DisposeWith(disposables);
|
||||
this.WhenAnyValue(x => x.PasswordErrorLabel.Text, text => !string.IsNullOrWhiteSpace(text))
|
||||
.BindTo(this, x => x.PasswordErrorLabel.IsVisible)
|
||||
.DisposeWith(disposables);
|
||||
this.WhenAnyValue(x => x.FormErrorLabel.Text, text => !string.IsNullOrWhiteSpace(text))
|
||||
.BindTo(this, x => x.FormErrorLabel.IsVisible)
|
||||
.DisposeWith(disposables);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,43 +7,42 @@ using ReactiveUI.Validation.Formatters;
|
|||
using ReactiveUI.XamForms;
|
||||
using Xamarin.Forms.Xaml;
|
||||
|
||||
namespace Camelotia.Presentation.Xamarin.Views
|
||||
{
|
||||
[XamlCompilation(XamlCompilationOptions.Compile)]
|
||||
public partial class HostAuthView : ReactiveContentPage<IHostAuthViewModel>
|
||||
{
|
||||
public HostAuthView()
|
||||
{
|
||||
InitializeComponent();
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
this.BindValidation(ViewModel, x => x.Address, x => x.HostNameErrorLabel.Text)
|
||||
.DisposeWith(disposables);
|
||||
this.BindValidation(ViewModel, x => x.Port, x => x.PortErrorLabel.Text)
|
||||
.DisposeWith(disposables);
|
||||
this.BindValidation(ViewModel, x => x.Username, x => x.UserNameErrorLabel.Text)
|
||||
.DisposeWith(disposables);
|
||||
this.BindValidation(ViewModel, x => x.Password, x => x.PasswordErrorLabel.Text)
|
||||
.DisposeWith(disposables);
|
||||
this.BindValidation(ViewModel, x => x.FormErrorLabel.Text, new SingleLineFormatter(Environment.NewLine))
|
||||
.DisposeWith(disposables);
|
||||
namespace Camelotia.Presentation.Xamarin.Views;
|
||||
|
||||
this.WhenAnyValue(x => x.HostNameErrorLabel.Text, text => !string.IsNullOrWhiteSpace(text))
|
||||
.BindTo(this, x => x.HostNameErrorLabel.IsVisible)
|
||||
.DisposeWith(disposables);
|
||||
this.WhenAnyValue(x => x.PortErrorLabel.Text, text => !string.IsNullOrWhiteSpace(text))
|
||||
.BindTo(this, x => x.PortErrorLabel.IsVisible)
|
||||
.DisposeWith(disposables);
|
||||
this.WhenAnyValue(x => x.UserNameErrorLabel.Text, text => !string.IsNullOrWhiteSpace(text))
|
||||
.BindTo(this, x => x.UserNameErrorLabel.IsVisible)
|
||||
.DisposeWith(disposables);
|
||||
this.WhenAnyValue(x => x.PasswordErrorLabel.Text, text => !string.IsNullOrWhiteSpace(text))
|
||||
.BindTo(this, x => x.PasswordErrorLabel.IsVisible)
|
||||
.DisposeWith(disposables);
|
||||
this.WhenAnyValue(x => x.FormErrorLabel.Text, text => !string.IsNullOrWhiteSpace(text))
|
||||
.BindTo(this, x => x.FormErrorLabel.IsVisible)
|
||||
.DisposeWith(disposables);
|
||||
});
|
||||
}
|
||||
[XamlCompilation(XamlCompilationOptions.Compile)]
|
||||
public partial class HostAuthView : ReactiveContentPage<IHostAuthViewModel>
|
||||
{
|
||||
public HostAuthView()
|
||||
{
|
||||
InitializeComponent();
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
this.BindValidation(ViewModel, x => x.Address, x => x.HostNameErrorLabel.Text)
|
||||
.DisposeWith(disposables);
|
||||
this.BindValidation(ViewModel, x => x.Port, x => x.PortErrorLabel.Text)
|
||||
.DisposeWith(disposables);
|
||||
this.BindValidation(ViewModel, x => x.Username, x => x.UserNameErrorLabel.Text)
|
||||
.DisposeWith(disposables);
|
||||
this.BindValidation(ViewModel, x => x.Password, x => x.PasswordErrorLabel.Text)
|
||||
.DisposeWith(disposables);
|
||||
this.BindValidation(ViewModel, x => x.FormErrorLabel.Text, new SingleLineFormatter(Environment.NewLine))
|
||||
.DisposeWith(disposables);
|
||||
|
||||
this.WhenAnyValue(x => x.HostNameErrorLabel.Text, text => !string.IsNullOrWhiteSpace(text))
|
||||
.BindTo(this, x => x.HostNameErrorLabel.IsVisible)
|
||||
.DisposeWith(disposables);
|
||||
this.WhenAnyValue(x => x.PortErrorLabel.Text, text => !string.IsNullOrWhiteSpace(text))
|
||||
.BindTo(this, x => x.PortErrorLabel.IsVisible)
|
||||
.DisposeWith(disposables);
|
||||
this.WhenAnyValue(x => x.UserNameErrorLabel.Text, text => !string.IsNullOrWhiteSpace(text))
|
||||
.BindTo(this, x => x.UserNameErrorLabel.IsVisible)
|
||||
.DisposeWith(disposables);
|
||||
this.WhenAnyValue(x => x.PasswordErrorLabel.Text, text => !string.IsNullOrWhiteSpace(text))
|
||||
.BindTo(this, x => x.PasswordErrorLabel.IsVisible)
|
||||
.DisposeWith(disposables);
|
||||
this.WhenAnyValue(x => x.FormErrorLabel.Text, text => !string.IsNullOrWhiteSpace(text))
|
||||
.BindTo(this, x => x.FormErrorLabel.IsVisible)
|
||||
.DisposeWith(disposables);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,15 +3,14 @@ using ReactiveUI;
|
|||
using ReactiveUI.XamForms;
|
||||
using Xamarin.Forms.Xaml;
|
||||
|
||||
namespace Camelotia.Presentation.Xamarin.Views
|
||||
namespace Camelotia.Presentation.Xamarin.Views;
|
||||
|
||||
[XamlCompilation(XamlCompilationOptions.Compile)]
|
||||
public partial class MainCloudView : ReactiveViewCell<ICloudViewModel>
|
||||
{
|
||||
[XamlCompilation(XamlCompilationOptions.Compile)]
|
||||
public partial class MainCloudView : ReactiveViewCell<ICloudViewModel>
|
||||
public MainCloudView()
|
||||
{
|
||||
public MainCloudView()
|
||||
{
|
||||
InitializeComponent();
|
||||
this.WhenActivated(disposables => { });
|
||||
}
|
||||
InitializeComponent();
|
||||
this.WhenActivated(disposables => { });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Reactive.Disposables;
|
||||
using System.Reactive.Linq;
|
||||
using Camelotia.Presentation.Interfaces;
|
||||
|
@ -9,92 +8,91 @@ using ReactiveUI.XamForms;
|
|||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Xaml;
|
||||
|
||||
namespace Camelotia.Presentation.Xamarin.Views
|
||||
namespace Camelotia.Presentation.Xamarin.Views;
|
||||
|
||||
[XamlCompilation(XamlCompilationOptions.Compile)]
|
||||
public partial class MainMasterView : ReactiveContentPage<IMainViewModel>, IDisposable
|
||||
{
|
||||
[XamlCompilation(XamlCompilationOptions.Compile)]
|
||||
public partial class MainMasterView : ReactiveContentPage<IMainViewModel>, IDisposable
|
||||
private CompositeDisposable _listeners;
|
||||
|
||||
public MainMasterView()
|
||||
{
|
||||
private CompositeDisposable _listeners;
|
||||
|
||||
public MainMasterView()
|
||||
InitializeComponent();
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
InitializeComponent();
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
OpenButton
|
||||
.Events()
|
||||
.Clicked
|
||||
.Select(args => ViewModel.SelectedProvider)
|
||||
.Where(provider => provider != null)
|
||||
.Select(x => new CloudExplorerView { ViewModel = x })
|
||||
.Subscribe(NavigateToProvider)
|
||||
.DisposeWith(disposables);
|
||||
});
|
||||
}
|
||||
OpenButton
|
||||
.Events()
|
||||
.Clicked
|
||||
.Select(args => ViewModel.SelectedProvider)
|
||||
.Where(provider => provider != null)
|
||||
.Select(x => new CloudExplorerView { ViewModel = x })
|
||||
.Subscribe(NavigateToProvider)
|
||||
.DisposeWith(disposables);
|
||||
});
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
_listeners.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private void NavigateToProvider(CloudExplorerView view)
|
||||
{
|
||||
_listeners?.Dispose();
|
||||
_listeners = new CompositeDisposable();
|
||||
|
||||
view.WhenAnyValue(x => x.ViewModel.Auth.IsAuthenticated)
|
||||
.Where(authenticated => authenticated)
|
||||
.Select(x => new CloudExplorerView { ViewModel = ViewModel.SelectedProvider })
|
||||
.Subscribe(NavigateWithoutBackStack)
|
||||
.DisposeWith(_listeners);
|
||||
|
||||
view.WhenAnyValue(x => x.ViewModel.Auth.IsAuthenticated)
|
||||
.Where(authenticated => !authenticated)
|
||||
.Select(x => new AuthView { ViewModel = ViewModel.SelectedProvider.Auth })
|
||||
.Subscribe(NavigateWithoutBackStack)
|
||||
.DisposeWith(_listeners);
|
||||
|
||||
view.WhenAnyValue(x => x.ViewModel.Folder.IsVisible)
|
||||
.Where(visible => visible)
|
||||
.Select(x => new CreateFolderView { ViewModel = ViewModel.SelectedProvider.Folder })
|
||||
.Subscribe(NavigateWithoutBackStack)
|
||||
.DisposeWith(_listeners);
|
||||
|
||||
view.WhenAnyValue(x => x.ViewModel.Folder.IsVisible)
|
||||
.Where(visible => !visible)
|
||||
.Skip(1)
|
||||
.Select(x => new CloudExplorerView { ViewModel = ViewModel.SelectedProvider })
|
||||
.Subscribe(NavigateWithoutBackStack)
|
||||
.DisposeWith(_listeners);
|
||||
|
||||
view.WhenAnyValue(x => x.ViewModel.Rename.IsVisible)
|
||||
.Where(visible => visible)
|
||||
.Select(x => new RenameFileView { ViewModel = ViewModel.SelectedProvider.Rename })
|
||||
.Subscribe(NavigateWithoutBackStack)
|
||||
.DisposeWith(_listeners);
|
||||
|
||||
view.WhenAnyValue(x => x.ViewModel.Rename.IsVisible)
|
||||
.Where(visible => !visible)
|
||||
.Skip(1)
|
||||
.Select(x => new CloudExplorerView { ViewModel = ViewModel.SelectedProvider })
|
||||
.Subscribe(NavigateWithoutBackStack)
|
||||
.DisposeWith(_listeners);
|
||||
}
|
||||
|
||||
private async void NavigateWithoutBackStack(Page page)
|
||||
{
|
||||
while (Navigation.NavigationStack.Count > 1)
|
||||
await Navigation.PopAsync(false).ConfigureAwait(false);
|
||||
await Navigation.PushAsync(page).ConfigureAwait(false);
|
||||
_listeners.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private void NavigateToProvider(CloudExplorerView view)
|
||||
{
|
||||
_listeners?.Dispose();
|
||||
_listeners = new CompositeDisposable();
|
||||
|
||||
view.WhenAnyValue(x => x.ViewModel.Auth.IsAuthenticated)
|
||||
.Where(authenticated => authenticated)
|
||||
.Select(x => new CloudExplorerView { ViewModel = ViewModel.SelectedProvider })
|
||||
.Subscribe(NavigateWithoutBackStack)
|
||||
.DisposeWith(_listeners);
|
||||
|
||||
view.WhenAnyValue(x => x.ViewModel.Auth.IsAuthenticated)
|
||||
.Where(authenticated => !authenticated)
|
||||
.Select(x => new AuthView { ViewModel = ViewModel.SelectedProvider.Auth })
|
||||
.Subscribe(NavigateWithoutBackStack)
|
||||
.DisposeWith(_listeners);
|
||||
|
||||
view.WhenAnyValue(x => x.ViewModel.Folder.IsVisible)
|
||||
.Where(visible => visible)
|
||||
.Select(x => new CreateFolderView { ViewModel = ViewModel.SelectedProvider.Folder })
|
||||
.Subscribe(NavigateWithoutBackStack)
|
||||
.DisposeWith(_listeners);
|
||||
|
||||
view.WhenAnyValue(x => x.ViewModel.Folder.IsVisible)
|
||||
.Where(visible => !visible)
|
||||
.Skip(1)
|
||||
.Select(x => new CloudExplorerView { ViewModel = ViewModel.SelectedProvider })
|
||||
.Subscribe(NavigateWithoutBackStack)
|
||||
.DisposeWith(_listeners);
|
||||
|
||||
view.WhenAnyValue(x => x.ViewModel.Rename.IsVisible)
|
||||
.Where(visible => visible)
|
||||
.Select(x => new RenameFileView { ViewModel = ViewModel.SelectedProvider.Rename })
|
||||
.Subscribe(NavigateWithoutBackStack)
|
||||
.DisposeWith(_listeners);
|
||||
|
||||
view.WhenAnyValue(x => x.ViewModel.Rename.IsVisible)
|
||||
.Where(visible => !visible)
|
||||
.Skip(1)
|
||||
.Select(x => new CloudExplorerView { ViewModel = ViewModel.SelectedProvider })
|
||||
.Subscribe(NavigateWithoutBackStack)
|
||||
.DisposeWith(_listeners);
|
||||
}
|
||||
|
||||
private async void NavigateWithoutBackStack(Page page)
|
||||
{
|
||||
while (Navigation.NavigationStack.Count > 1)
|
||||
await Navigation.PopAsync(false).ConfigureAwait(false);
|
||||
await Navigation.PushAsync(page).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,21 +6,20 @@ using ReactiveUI;
|
|||
using ReactiveUI.XamForms;
|
||||
using Xamarin.Forms.Xaml;
|
||||
|
||||
namespace Camelotia.Presentation.Xamarin.Views
|
||||
namespace Camelotia.Presentation.Xamarin.Views;
|
||||
|
||||
[XamlCompilation(XamlCompilationOptions.Compile)]
|
||||
public partial class MainView : ReactiveNavigationPage<IMainViewModel>
|
||||
{
|
||||
[XamlCompilation(XamlCompilationOptions.Compile)]
|
||||
public partial class MainView : ReactiveNavigationPage<IMainViewModel>
|
||||
public MainView()
|
||||
{
|
||||
public MainView()
|
||||
InitializeComponent();
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
InitializeComponent();
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
this.WhenAnyValue(x => x.ViewModel)
|
||||
.Select(x => new MainMasterView { ViewModel = x })
|
||||
.Subscribe(view => PushAsync(view))
|
||||
.DisposeWith(disposables);
|
||||
});
|
||||
}
|
||||
this.WhenAnyValue(x => x.ViewModel)
|
||||
.Select(x => new MainMasterView { ViewModel = x })
|
||||
.Subscribe(view => PushAsync(view))
|
||||
.DisposeWith(disposables);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,15 +3,14 @@ using ReactiveUI;
|
|||
using ReactiveUI.XamForms;
|
||||
using Xamarin.Forms.Xaml;
|
||||
|
||||
namespace Camelotia.Presentation.Xamarin.Views
|
||||
namespace Camelotia.Presentation.Xamarin.Views;
|
||||
|
||||
[XamlCompilation(XamlCompilationOptions.Compile)]
|
||||
public partial class OAuthView : ReactiveContentPage<IOAuthViewModel>
|
||||
{
|
||||
[XamlCompilation(XamlCompilationOptions.Compile)]
|
||||
public partial class OAuthView : ReactiveContentPage<IOAuthViewModel>
|
||||
public OAuthView()
|
||||
{
|
||||
public OAuthView()
|
||||
{
|
||||
InitializeComponent();
|
||||
this.WhenActivated(disposables => { });
|
||||
}
|
||||
InitializeComponent();
|
||||
this.WhenActivated(disposables => { });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,28 +7,27 @@ using ReactiveUI.Validation.Formatters;
|
|||
using ReactiveUI.XamForms;
|
||||
using Xamarin.Forms.Xaml;
|
||||
|
||||
namespace Camelotia.Presentation.Xamarin.Views
|
||||
{
|
||||
[XamlCompilation(XamlCompilationOptions.Compile)]
|
||||
public partial class RenameFileView : ReactiveContentPage<IRenameFileViewModel>
|
||||
{
|
||||
public RenameFileView()
|
||||
{
|
||||
InitializeComponent();
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
this.BindValidation(ViewModel, x => x.NewName, x => x.FileNameErrorLabel.Text)
|
||||
.DisposeWith(disposables);
|
||||
this.BindValidation(ViewModel, x => x.FormErrorLabel.Text, new SingleLineFormatter(Environment.NewLine))
|
||||
.DisposeWith(disposables);
|
||||
namespace Camelotia.Presentation.Xamarin.Views;
|
||||
|
||||
this.WhenAnyValue(x => x.FileNameErrorLabel.Text, text => !string.IsNullOrWhiteSpace(text))
|
||||
.BindTo(this, x => x.FileNameErrorLabel.IsVisible)
|
||||
.DisposeWith(disposables);
|
||||
this.WhenAnyValue(x => x.FormErrorLabel.Text, text => !string.IsNullOrWhiteSpace(text))
|
||||
.BindTo(this, x => x.FormErrorLabel.IsVisible)
|
||||
.DisposeWith(disposables);
|
||||
});
|
||||
}
|
||||
[XamlCompilation(XamlCompilationOptions.Compile)]
|
||||
public partial class RenameFileView : ReactiveContentPage<IRenameFileViewModel>
|
||||
{
|
||||
public RenameFileView()
|
||||
{
|
||||
InitializeComponent();
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
this.BindValidation(ViewModel, x => x.NewName, x => x.FileNameErrorLabel.Text)
|
||||
.DisposeWith(disposables);
|
||||
this.BindValidation(ViewModel, x => x.FormErrorLabel.Text, new SingleLineFormatter(Environment.NewLine))
|
||||
.DisposeWith(disposables);
|
||||
|
||||
this.WhenAnyValue(x => x.FileNameErrorLabel.Text, text => !string.IsNullOrWhiteSpace(text))
|
||||
.BindTo(this, x => x.FileNameErrorLabel.IsVisible)
|
||||
.DisposeWith(disposables);
|
||||
this.WhenAnyValue(x => x.FormErrorLabel.Text, text => !string.IsNullOrWhiteSpace(text))
|
||||
.BindTo(this, x => x.FormErrorLabel.IsVisible)
|
||||
.DisposeWith(disposables);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +1,13 @@
|
|||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Camelotia.Presentation.AppState
|
||||
{
|
||||
[DataContract]
|
||||
public class AuthState
|
||||
{
|
||||
[DataMember]
|
||||
public DirectAuthState DirectAuthState { get; set; } = new DirectAuthState();
|
||||
namespace Camelotia.Presentation.AppState;
|
||||
|
||||
[DataMember]
|
||||
public HostAuthState HostAuthState { get; set; } = new HostAuthState();
|
||||
}
|
||||
}
|
||||
[DataContract]
|
||||
public class AuthState
|
||||
{
|
||||
[DataMember]
|
||||
public DirectAuthState DirectAuthState { get; set; } = new();
|
||||
|
||||
[DataMember]
|
||||
public HostAuthState HostAuthState { get; set; } = new();
|
||||
}
|
||||
|
|
|
@ -2,46 +2,45 @@ using System;
|
|||
using System.Runtime.Serialization;
|
||||
using Camelotia.Services.Models;
|
||||
|
||||
namespace Camelotia.Presentation.AppState
|
||||
namespace Camelotia.Presentation.AppState;
|
||||
|
||||
[DataContract]
|
||||
public class CloudState
|
||||
{
|
||||
[DataContract]
|
||||
public class CloudState
|
||||
[DataMember]
|
||||
public CreateFolderState CreateFolderState { get; set; } = new();
|
||||
|
||||
[DataMember]
|
||||
public RenameFileState RenameFileState { get; set; } = new();
|
||||
|
||||
[DataMember]
|
||||
public AuthState AuthState { get; set; } = new();
|
||||
|
||||
[DataMember]
|
||||
public string CurrentPath { get; set; }
|
||||
|
||||
[DataMember]
|
||||
public Guid Id { get; set; } = Guid.NewGuid();
|
||||
|
||||
[DataMember]
|
||||
public DateTime Created { get; set; } = DateTime.Now;
|
||||
|
||||
[DataMember]
|
||||
public CloudType Type { get; set; } = CloudType.Local;
|
||||
|
||||
[DataMember]
|
||||
public string User { get; set; }
|
||||
|
||||
[DataMember]
|
||||
public string Token { get; set; }
|
||||
|
||||
[IgnoreDataMember]
|
||||
public CloudParameters Parameters => new()
|
||||
{
|
||||
[DataMember]
|
||||
public CreateFolderState CreateFolderState { get; set; } = new CreateFolderState();
|
||||
|
||||
[DataMember]
|
||||
public RenameFileState RenameFileState { get; set; } = new RenameFileState();
|
||||
|
||||
[DataMember]
|
||||
public AuthState AuthState { get; set; } = new AuthState();
|
||||
|
||||
[DataMember]
|
||||
public string CurrentPath { get; set; }
|
||||
|
||||
[DataMember]
|
||||
public Guid Id { get; set; } = Guid.NewGuid();
|
||||
|
||||
[DataMember]
|
||||
public DateTime Created { get; set; } = DateTime.Now;
|
||||
|
||||
[DataMember]
|
||||
public CloudType Type { get; set; } = CloudType.Local;
|
||||
|
||||
[DataMember]
|
||||
public string User { get; set; }
|
||||
|
||||
[DataMember]
|
||||
public string Token { get; set; }
|
||||
|
||||
[IgnoreDataMember]
|
||||
public CloudParameters Parameters => new CloudParameters
|
||||
{
|
||||
Id = Id,
|
||||
Created = Created,
|
||||
Type = Type,
|
||||
User = User,
|
||||
Token = Token
|
||||
};
|
||||
}
|
||||
}
|
||||
Id = Id,
|
||||
Created = Created,
|
||||
Type = Type,
|
||||
User = User,
|
||||
Token = Token
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,14 +1,13 @@
|
|||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Camelotia.Presentation.AppState
|
||||
{
|
||||
[DataContract]
|
||||
public class CreateFolderState
|
||||
{
|
||||
[DataMember]
|
||||
public string Name { get; set; }
|
||||
namespace Camelotia.Presentation.AppState;
|
||||
|
||||
[DataMember]
|
||||
public bool IsVisible { get; set; }
|
||||
}
|
||||
[DataContract]
|
||||
public class CreateFolderState
|
||||
{
|
||||
[DataMember]
|
||||
public string Name { get; set; }
|
||||
|
||||
[DataMember]
|
||||
public bool IsVisible { get; set; }
|
||||
}
|
|
@ -1,14 +1,13 @@
|
|||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Camelotia.Presentation.AppState
|
||||
{
|
||||
[DataContract]
|
||||
public class DirectAuthState
|
||||
{
|
||||
[DataMember]
|
||||
public string Username { get; set; }
|
||||
namespace Camelotia.Presentation.AppState;
|
||||
|
||||
[DataMember]
|
||||
public string Password { get; set; }
|
||||
}
|
||||
[DataContract]
|
||||
public class DirectAuthState
|
||||
{
|
||||
[DataMember]
|
||||
public string Username { get; set; }
|
||||
|
||||
[DataMember]
|
||||
public string Password { get; set; }
|
||||
}
|
|
@ -1,20 +1,19 @@
|
|||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Camelotia.Presentation.AppState
|
||||
namespace Camelotia.Presentation.AppState;
|
||||
|
||||
[DataContract]
|
||||
public class HostAuthState
|
||||
{
|
||||
[DataContract]
|
||||
public class HostAuthState
|
||||
{
|
||||
[DataMember]
|
||||
public string Username { get; set; }
|
||||
[DataMember]
|
||||
public string Username { get; set; }
|
||||
|
||||
[DataMember]
|
||||
public string Password { get; set; }
|
||||
[DataMember]
|
||||
public string Password { get; set; }
|
||||
|
||||
[DataMember]
|
||||
public string Address { get; set; }
|
||||
[DataMember]
|
||||
public string Address { get; set; }
|
||||
|
||||
[DataMember]
|
||||
public string Port { get; set; }
|
||||
}
|
||||
[DataMember]
|
||||
public string Port { get; set; }
|
||||
}
|
|
@ -6,28 +6,27 @@ using Camelotia.Services.Configuration;
|
|||
using Camelotia.Services.Models;
|
||||
using DynamicData;
|
||||
|
||||
namespace Camelotia.Presentation.AppState
|
||||
namespace Camelotia.Presentation.AppState;
|
||||
|
||||
[DataContract]
|
||||
public class MainState
|
||||
{
|
||||
[DataContract]
|
||||
public class MainState
|
||||
[IgnoreDataMember]
|
||||
public SourceCache<CloudState, Guid> Clouds { get; } = new(x => x.Id);
|
||||
|
||||
[DataMember]
|
||||
public IEnumerable<CloudState> CloudStates
|
||||
{
|
||||
[IgnoreDataMember]
|
||||
public SourceCache<CloudState, Guid> Clouds { get; } = new SourceCache<CloudState, Guid>(x => x.Id);
|
||||
|
||||
[DataMember]
|
||||
public IEnumerable<CloudState> CloudStates
|
||||
{
|
||||
get => Clouds.Items.ToList();
|
||||
set => Clouds.AddOrUpdate(value);
|
||||
}
|
||||
|
||||
[DataMember]
|
||||
public CloudType? SelectedSupportedType { get; set; }
|
||||
|
||||
[DataMember]
|
||||
public Guid SelectedProviderId { get; set; }
|
||||
|
||||
[DataMember]
|
||||
public CloudConfiguration CloudConfiguration { get; set; } = new CloudConfiguration();
|
||||
get => Clouds.Items.ToList();
|
||||
set => Clouds.AddOrUpdate(value);
|
||||
}
|
||||
|
||||
[DataMember]
|
||||
public CloudType? SelectedSupportedType { get; set; }
|
||||
|
||||
[DataMember]
|
||||
public Guid SelectedProviderId { get; set; }
|
||||
|
||||
[DataMember]
|
||||
public CloudConfiguration CloudConfiguration { get; set; } = new();
|
||||
}
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Camelotia.Presentation.AppState
|
||||
namespace Camelotia.Presentation.AppState;
|
||||
|
||||
[DataContract]
|
||||
public class RenameFileState
|
||||
{
|
||||
[DataContract]
|
||||
public class RenameFileState
|
||||
{
|
||||
[DataMember]
|
||||
public string NewName { get; set; }
|
||||
}
|
||||
[DataMember]
|
||||
public string NewName { get; set; }
|
||||
}
|
|
@ -1,24 +1,23 @@
|
|||
using Camelotia.Presentation.Interfaces;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace Camelotia.Presentation.DesignTime
|
||||
namespace Camelotia.Presentation.DesignTime;
|
||||
|
||||
public class DesignTimeAuthViewModel : ReactiveObject, IAuthViewModel
|
||||
{
|
||||
public class DesignTimeAuthViewModel : ReactiveObject, IAuthViewModel
|
||||
{
|
||||
public IDirectAuthViewModel DirectAuth { get; } = new DesignTimeDirectAuthViewModel();
|
||||
public IDirectAuthViewModel DirectAuth { get; } = new DesignTimeDirectAuthViewModel();
|
||||
|
||||
public IHostAuthViewModel HostAuth { get; } = new DesignTimeHostAuthViewModel();
|
||||
public IHostAuthViewModel HostAuth { get; } = new DesignTimeHostAuthViewModel();
|
||||
|
||||
public IOAuthViewModel OAuth { get; } = new DesignTimeOAuthViewModel();
|
||||
public IOAuthViewModel OAuth { get; } = new DesignTimeOAuthViewModel();
|
||||
|
||||
public bool SupportsDirectAuth { get; }
|
||||
public bool SupportsDirectAuth { get; }
|
||||
|
||||
public bool SupportsHostAuth { get; }
|
||||
public bool SupportsHostAuth { get; }
|
||||
|
||||
public bool SupportsOAuth { get; }
|
||||
public bool SupportsOAuth { get; }
|
||||
|
||||
public bool IsAuthenticated { get; } = true;
|
||||
public bool IsAuthenticated { get; } = true;
|
||||
|
||||
public bool IsAnonymous { get; }
|
||||
}
|
||||
public bool IsAnonymous { get; }
|
||||
}
|
|
@ -6,96 +6,95 @@ using Camelotia.Presentation.Interfaces;
|
|||
using Camelotia.Services.Models;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace Camelotia.Presentation.DesignTime
|
||||
namespace Camelotia.Presentation.DesignTime;
|
||||
|
||||
public class DesignTimeCloudViewModel : ReactiveObject, ICloudViewModel
|
||||
{
|
||||
public class DesignTimeCloudViewModel : ReactiveObject, ICloudViewModel
|
||||
public DesignTimeCloudViewModel()
|
||||
{
|
||||
public DesignTimeCloudViewModel()
|
||||
Files = new[]
|
||||
{
|
||||
Files = new[]
|
||||
{
|
||||
new DesignTimeFileViewModel(this),
|
||||
new DesignTimeFileViewModel(this)
|
||||
};
|
||||
SelectedFile = Files.FirstOrDefault();
|
||||
}
|
||||
|
||||
public Guid Id { get; } = Guid.NewGuid();
|
||||
|
||||
public IAuthViewModel Auth { get; } = new DesignTimeAuthViewModel();
|
||||
|
||||
public IRenameFileViewModel Rename { get; } = new DesignTimeRenameFileViewModel();
|
||||
|
||||
public ICreateFolderViewModel Folder { get; } = new DesignTimeCreateFolderViewModel();
|
||||
|
||||
public IFileViewModel SelectedFile { get; set; }
|
||||
|
||||
public IEnumerable<IFileViewModel> Files { get; }
|
||||
|
||||
public ReactiveCommand<Unit, Unit> DownloadSelectedFile { get; }
|
||||
|
||||
public ReactiveCommand<Unit, Unit> UploadToCurrentPath { get; }
|
||||
|
||||
public ReactiveCommand<Unit, Unit> DeleteSelectedFile { get; }
|
||||
|
||||
public ReactiveCommand<Unit, Unit> UnselectFile { get; }
|
||||
|
||||
public ReactiveCommand<Unit, IEnumerable<FileModel>> Refresh { get; }
|
||||
|
||||
public ReactiveCommand<Unit, Unit> Logout { get; }
|
||||
|
||||
public ReactiveCommand<Unit, string> Back { get; }
|
||||
|
||||
public ReactiveCommand<Unit, string> Open { get; }
|
||||
|
||||
public ReactiveCommand<string, string> SetPath { get; }
|
||||
|
||||
public bool IsCurrentPathEmpty { get; }
|
||||
|
||||
public bool IsLoading { get; }
|
||||
|
||||
public bool IsReady { get; } = true;
|
||||
|
||||
public bool HasErrorMessage { get; }
|
||||
|
||||
public bool CanLogout { get; }
|
||||
|
||||
public bool CanInteract { get; }
|
||||
|
||||
public bool ShowBreadCrumbs { get; } = true;
|
||||
|
||||
public bool HideBreadCrumbs { get; }
|
||||
|
||||
public int RefreshingIn { get; } = 30;
|
||||
|
||||
public string CurrentPath { get; } = "/home/files";
|
||||
|
||||
public IEnumerable<IFolderViewModel> BreadCrumbs { get; } = new List<IFolderViewModel>
|
||||
{
|
||||
new DesignTimeFolderViewModel(
|
||||
"home",
|
||||
new[]
|
||||
{
|
||||
new DesignTimeFolderViewModel("home"),
|
||||
new DesignTimeFolderViewModel("home1"),
|
||||
new DesignTimeFolderViewModel("home2")
|
||||
}),
|
||||
new DesignTimeFolderViewModel(
|
||||
"files",
|
||||
new[]
|
||||
{
|
||||
new DesignTimeFolderViewModel("files"),
|
||||
new DesignTimeFolderViewModel("files1"),
|
||||
new DesignTimeFolderViewModel("files2")
|
||||
})
|
||||
new DesignTimeFileViewModel(this),
|
||||
new DesignTimeFileViewModel(this)
|
||||
};
|
||||
|
||||
public string Description { get; } = "Mock file system.";
|
||||
|
||||
public DateTime Created { get; } = DateTime.Now;
|
||||
|
||||
public string Name { get; } = "Awesome mock";
|
||||
|
||||
public string Size { get; } = "42MB";
|
||||
SelectedFile = Files.FirstOrDefault();
|
||||
}
|
||||
|
||||
public Guid Id { get; } = Guid.NewGuid();
|
||||
|
||||
public IAuthViewModel Auth { get; } = new DesignTimeAuthViewModel();
|
||||
|
||||
public IRenameFileViewModel Rename { get; } = new DesignTimeRenameFileViewModel();
|
||||
|
||||
public ICreateFolderViewModel Folder { get; } = new DesignTimeCreateFolderViewModel();
|
||||
|
||||
public IFileViewModel SelectedFile { get; set; }
|
||||
|
||||
public IEnumerable<IFileViewModel> Files { get; }
|
||||
|
||||
public ReactiveCommand<Unit, Unit> DownloadSelectedFile { get; }
|
||||
|
||||
public ReactiveCommand<Unit, Unit> UploadToCurrentPath { get; }
|
||||
|
||||
public ReactiveCommand<Unit, Unit> DeleteSelectedFile { get; }
|
||||
|
||||
public ReactiveCommand<Unit, Unit> UnselectFile { get; }
|
||||
|
||||
public ReactiveCommand<Unit, IEnumerable<FileModel>> Refresh { get; }
|
||||
|
||||
public ReactiveCommand<Unit, Unit> Logout { get; }
|
||||
|
||||
public ReactiveCommand<Unit, string> Back { get; }
|
||||
|
||||
public ReactiveCommand<Unit, string> Open { get; }
|
||||
|
||||
public ReactiveCommand<string, string> SetPath { get; }
|
||||
|
||||
public bool IsCurrentPathEmpty { get; }
|
||||
|
||||
public bool IsLoading { get; }
|
||||
|
||||
public bool IsReady { get; } = true;
|
||||
|
||||
public bool HasErrorMessage { get; }
|
||||
|
||||
public bool CanLogout { get; }
|
||||
|
||||
public bool CanInteract { get; }
|
||||
|
||||
public bool ShowBreadCrumbs { get; } = true;
|
||||
|
||||
public bool HideBreadCrumbs { get; }
|
||||
|
||||
public int RefreshingIn { get; } = 30;
|
||||
|
||||
public string CurrentPath { get; } = "/home/files";
|
||||
|
||||
public IEnumerable<IFolderViewModel> BreadCrumbs { get; } = new List<IFolderViewModel>
|
||||
{
|
||||
new DesignTimeFolderViewModel(
|
||||
"home",
|
||||
new[]
|
||||
{
|
||||
new DesignTimeFolderViewModel("home"),
|
||||
new DesignTimeFolderViewModel("home1"),
|
||||
new DesignTimeFolderViewModel("home2")
|
||||
}),
|
||||
new DesignTimeFolderViewModel(
|
||||
"files",
|
||||
new[]
|
||||
{
|
||||
new DesignTimeFolderViewModel("files"),
|
||||
new DesignTimeFolderViewModel("files1"),
|
||||
new DesignTimeFolderViewModel("files2")
|
||||
})
|
||||
};
|
||||
|
||||
public string Description { get; } = "Mock file system.";
|
||||
|
||||
public DateTime Created { get; } = DateTime.Now;
|
||||
|
||||
public string Name { get; } = "Awesome mock";
|
||||
|
||||
public string Size { get; } = "42MB";
|
||||
}
|
|
@ -4,28 +4,27 @@ using ReactiveUI;
|
|||
using ReactiveUI.Validation.Extensions;
|
||||
using ReactiveUI.Validation.Helpers;
|
||||
|
||||
namespace Camelotia.Presentation.DesignTime
|
||||
namespace Camelotia.Presentation.DesignTime;
|
||||
|
||||
public class DesignTimeCreateFolderViewModel : ReactiveValidationObject, ICreateFolderViewModel
|
||||
{
|
||||
public class DesignTimeCreateFolderViewModel : ReactiveValidationObject, ICreateFolderViewModel
|
||||
{
|
||||
public DesignTimeCreateFolderViewModel() => this.ValidationRule(x => x.Name, _ => false, "Validation error.");
|
||||
public DesignTimeCreateFolderViewModel() => this.ValidationRule(x => x.Name, _ => false, "Validation error.");
|
||||
|
||||
public bool IsLoading { get; }
|
||||
public bool IsLoading { get; }
|
||||
|
||||
public bool IsVisible { get; set; }
|
||||
public bool IsVisible { get; set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
public string Name { get; set; }
|
||||
|
||||
public string Path { get; } = "/home/path";
|
||||
public string Path { get; } = "/home/path";
|
||||
|
||||
public bool HasErrorMessage { get; } = true;
|
||||
public bool HasErrorMessage { get; } = true;
|
||||
|
||||
public string ErrorMessage { get; } = "Error message example.";
|
||||
public string ErrorMessage { get; } = "Error message example.";
|
||||
|
||||
public ReactiveCommand<Unit, Unit> Create { get; }
|
||||
public ReactiveCommand<Unit, Unit> Create { get; }
|
||||
|
||||
public ReactiveCommand<Unit, Unit> Close { get; }
|
||||
public ReactiveCommand<Unit, Unit> Close { get; }
|
||||
|
||||
public ReactiveCommand<Unit, Unit> Open { get; }
|
||||
}
|
||||
public ReactiveCommand<Unit, Unit> Open { get; }
|
||||
}
|
|
@ -4,22 +4,21 @@ using ReactiveUI;
|
|||
using ReactiveUI.Validation.Extensions;
|
||||
using ReactiveUI.Validation.Helpers;
|
||||
|
||||
namespace Camelotia.Presentation.DesignTime
|
||||
namespace Camelotia.Presentation.DesignTime;
|
||||
|
||||
public class DesignTimeDirectAuthViewModel : ReactiveValidationObject, IDirectAuthViewModel
|
||||
{
|
||||
public class DesignTimeDirectAuthViewModel : ReactiveValidationObject, IDirectAuthViewModel
|
||||
{
|
||||
public DesignTimeDirectAuthViewModel() => this.ValidationRule(x => x.Username, name => false, "Validation error.");
|
||||
public DesignTimeDirectAuthViewModel() => this.ValidationRule(x => x.Username, name => false, "Validation error.");
|
||||
|
||||
public string Username { get; set; } = "Joseph";
|
||||
public string Username { get; set; } = "Joseph";
|
||||
|
||||
public string Password { get; set; }
|
||||
public string Password { get; set; }
|
||||
|
||||
public ReactiveCommand<Unit, Unit> Login { get; }
|
||||
public ReactiveCommand<Unit, Unit> Login { get; }
|
||||
|
||||
public bool HasErrorMessage { get; } = true;
|
||||
public bool HasErrorMessage { get; } = true;
|
||||
|
||||
public string ErrorMessage { get; } = "Error message example.";
|
||||
public string ErrorMessage { get; } = "Error message example.";
|
||||
|
||||
public bool IsBusy { get; }
|
||||
}
|
||||
public bool IsBusy { get; }
|
||||
}
|
|
@ -3,29 +3,28 @@ using System.Globalization;
|
|||
using Camelotia.Presentation.Interfaces;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace Camelotia.Presentation.DesignTime
|
||||
namespace Camelotia.Presentation.DesignTime;
|
||||
|
||||
public class DesignTimeFileViewModel : ReactiveObject, IFileViewModel
|
||||
{
|
||||
public class DesignTimeFileViewModel : ReactiveObject, IFileViewModel
|
||||
public DesignTimeFileViewModel()
|
||||
: this(null)
|
||||
{
|
||||
public DesignTimeFileViewModel()
|
||||
: this(null)
|
||||
{
|
||||
}
|
||||
|
||||
public DesignTimeFileViewModel(DesignTimeCloudViewModel provider) => Provider = provider;
|
||||
|
||||
public string Name { get; } = "Awesome file.";
|
||||
|
||||
public ICloudViewModel Provider { get; }
|
||||
|
||||
public string Modified { get; } = DateTime.Now.ToString(CultureInfo.InvariantCulture);
|
||||
|
||||
public bool IsFolder { get; }
|
||||
|
||||
public bool IsFile { get; } = true;
|
||||
|
||||
public string Path { get; } = "/home/path/file";
|
||||
|
||||
public string Size { get; } = "42 KB";
|
||||
}
|
||||
|
||||
public DesignTimeFileViewModel(DesignTimeCloudViewModel provider) => Provider = provider;
|
||||
|
||||
public string Name { get; } = "Awesome file.";
|
||||
|
||||
public ICloudViewModel Provider { get; }
|
||||
|
||||
public string Modified { get; } = DateTime.Now.ToString(CultureInfo.InvariantCulture);
|
||||
|
||||
public bool IsFolder { get; }
|
||||
|
||||
public bool IsFile { get; } = true;
|
||||
|
||||
public string Path { get; } = "/home/path/file";
|
||||
|
||||
public string Size { get; } = "42 KB";
|
||||
}
|
|
@ -3,31 +3,30 @@ using System.Linq;
|
|||
using Camelotia.Presentation.Interfaces;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace Camelotia.Presentation.DesignTime
|
||||
namespace Camelotia.Presentation.DesignTime;
|
||||
|
||||
public class DesignTimeFolderViewModel : ReactiveObject, IFolderViewModel
|
||||
{
|
||||
public class DesignTimeFolderViewModel : ReactiveObject, IFolderViewModel
|
||||
public DesignTimeFolderViewModel()
|
||||
{
|
||||
public DesignTimeFolderViewModel()
|
||||
Name = "home";
|
||||
Children = new List<IFolderViewModel>
|
||||
{
|
||||
Name = "home";
|
||||
Children = new List<IFolderViewModel>
|
||||
{
|
||||
new DesignTimeFolderViewModel("home"),
|
||||
new DesignTimeFolderViewModel("home1"),
|
||||
new DesignTimeFolderViewModel("home2")
|
||||
};
|
||||
}
|
||||
|
||||
public DesignTimeFolderViewModel(string name, IEnumerable<IFolderViewModel> children = null)
|
||||
{
|
||||
Name = name;
|
||||
Children = children ?? Enumerable.Empty<IFolderViewModel>();
|
||||
}
|
||||
|
||||
public string Name { get; }
|
||||
|
||||
public string FullPath { get; }
|
||||
|
||||
public IEnumerable<IFolderViewModel> Children { get; }
|
||||
new DesignTimeFolderViewModel("home"),
|
||||
new DesignTimeFolderViewModel("home1"),
|
||||
new DesignTimeFolderViewModel("home2")
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public DesignTimeFolderViewModel(string name, IEnumerable<IFolderViewModel> children = null)
|
||||
{
|
||||
Name = name;
|
||||
Children = children ?? Enumerable.Empty<IFolderViewModel>();
|
||||
}
|
||||
|
||||
public string Name { get; }
|
||||
|
||||
public string FullPath { get; }
|
||||
|
||||
public IEnumerable<IFolderViewModel> Children { get; }
|
||||
}
|
|
@ -4,26 +4,25 @@ using ReactiveUI;
|
|||
using ReactiveUI.Validation.Extensions;
|
||||
using ReactiveUI.Validation.Helpers;
|
||||
|
||||
namespace Camelotia.Presentation.DesignTime
|
||||
namespace Camelotia.Presentation.DesignTime;
|
||||
|
||||
public class DesignTimeHostAuthViewModel : ReactiveValidationObject, IHostAuthViewModel
|
||||
{
|
||||
public class DesignTimeHostAuthViewModel : ReactiveValidationObject, IHostAuthViewModel
|
||||
{
|
||||
public DesignTimeHostAuthViewModel() => this.ValidationRule(x => x.Username, name => false, "Validation error.");
|
||||
public DesignTimeHostAuthViewModel() => this.ValidationRule(x => x.Username, name => false, "Validation error.");
|
||||
|
||||
public string Username { get; set; } = "Jotaro";
|
||||
public string Username { get; set; } = "Jotaro";
|
||||
|
||||
public string Password { get; set; } = "Qwerty";
|
||||
public string Password { get; set; } = "Qwerty";
|
||||
|
||||
public ReactiveCommand<Unit, Unit> Login { get; }
|
||||
public ReactiveCommand<Unit, Unit> Login { get; }
|
||||
|
||||
public bool HasErrorMessage { get; } = true;
|
||||
public bool HasErrorMessage { get; } = true;
|
||||
|
||||
public string ErrorMessage { get; } = "Error message example.";
|
||||
public string ErrorMessage { get; } = "Error message example.";
|
||||
|
||||
public bool IsBusy { get; }
|
||||
public bool IsBusy { get; }
|
||||
|
||||
public string Address { get; set; } = "127.0.0.1";
|
||||
public string Address { get; set; } = "127.0.0.1";
|
||||
|
||||
public string Port { get; set; } = "5001";
|
||||
}
|
||||
public string Port { get; set; } = "5001";
|
||||
}
|
|
@ -5,39 +5,38 @@ using Camelotia.Presentation.Interfaces;
|
|||
using Camelotia.Services.Models;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace Camelotia.Presentation.DesignTime
|
||||
namespace Camelotia.Presentation.DesignTime;
|
||||
|
||||
public class DesignTimeMainViewModel : ReactiveObject, IMainViewModel
|
||||
{
|
||||
public class DesignTimeMainViewModel : ReactiveObject, IMainViewModel
|
||||
{
|
||||
public ReadOnlyObservableCollection<ICloudViewModel> Clouds { get; } =
|
||||
new ReadOnlyObservableCollection<ICloudViewModel>(
|
||||
new ObservableCollection<ICloudViewModel>(
|
||||
new List<ICloudViewModel>
|
||||
{
|
||||
new DesignTimeCloudViewModel(),
|
||||
new DesignTimeCloudViewModel()
|
||||
}));
|
||||
public ReadOnlyObservableCollection<ICloudViewModel> Clouds { get; } =
|
||||
new(
|
||||
new ObservableCollection<ICloudViewModel>(
|
||||
new List<ICloudViewModel>
|
||||
{
|
||||
new DesignTimeCloudViewModel(),
|
||||
new DesignTimeCloudViewModel()
|
||||
}));
|
||||
|
||||
public ICloudViewModel SelectedProvider { get; set; } = new DesignTimeCloudViewModel();
|
||||
public ICloudViewModel SelectedProvider { get; set; } = new DesignTimeCloudViewModel();
|
||||
|
||||
public IEnumerable<CloudType> SupportedTypes { get; } = new[] { CloudType.Ftp, CloudType.Sftp };
|
||||
public IEnumerable<CloudType> SupportedTypes { get; } = new[] { CloudType.Ftp, CloudType.Sftp };
|
||||
|
||||
public CloudType SelectedSupportedType { get; set; } = CloudType.Sftp;
|
||||
public CloudType SelectedSupportedType { get; set; } = CloudType.Sftp;
|
||||
|
||||
public bool WelcomeScreenCollapsed { get; } = true;
|
||||
public bool WelcomeScreenCollapsed { get; } = true;
|
||||
|
||||
public bool WelcomeScreenVisible { get; }
|
||||
public bool WelcomeScreenVisible { get; }
|
||||
|
||||
public ReactiveCommand<Unit, Unit> Unselect { get; }
|
||||
public ReactiveCommand<Unit, Unit> Unselect { get; }
|
||||
|
||||
public ReactiveCommand<Unit, Unit> Refresh { get; }
|
||||
public ReactiveCommand<Unit, Unit> Refresh { get; }
|
||||
|
||||
public ReactiveCommand<Unit, Unit> Remove { get; }
|
||||
public ReactiveCommand<Unit, Unit> Remove { get; }
|
||||
|
||||
public ReactiveCommand<Unit, Unit> Add { get; }
|
||||
public ReactiveCommand<Unit, Unit> Add { get; }
|
||||
|
||||
public bool IsLoading { get; }
|
||||
public bool IsLoading { get; }
|
||||
|
||||
public bool IsReady { get; } = true;
|
||||
}
|
||||
}
|
||||
public bool IsReady { get; } = true;
|
||||
}
|
||||
|
|
|
@ -2,16 +2,15 @@ using System.Reactive;
|
|||
using Camelotia.Presentation.Interfaces;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace Camelotia.Presentation.DesignTime
|
||||
namespace Camelotia.Presentation.DesignTime;
|
||||
|
||||
public class DesignTimeOAuthViewModel : ReactiveObject, IOAuthViewModel
|
||||
{
|
||||
public class DesignTimeOAuthViewModel : ReactiveObject, IOAuthViewModel
|
||||
{
|
||||
public ReactiveCommand<Unit, Unit> Login { get; }
|
||||
public ReactiveCommand<Unit, Unit> Login { get; }
|
||||
|
||||
public bool HasErrorMessage { get; } = true;
|
||||
public bool HasErrorMessage { get; } = true;
|
||||
|
||||
public string ErrorMessage { get; } = "Error message example.";
|
||||
public string ErrorMessage { get; } = "Error message example.";
|
||||
|
||||
public bool IsBusy { get; }
|
||||
}
|
||||
public bool IsBusy { get; }
|
||||
}
|
|
@ -4,28 +4,27 @@ using ReactiveUI;
|
|||
using ReactiveUI.Validation.Extensions;
|
||||
using ReactiveUI.Validation.Helpers;
|
||||
|
||||
namespace Camelotia.Presentation.DesignTime
|
||||
namespace Camelotia.Presentation.DesignTime;
|
||||
|
||||
public class DesignTimeRenameFileViewModel : ReactiveValidationObject, IRenameFileViewModel
|
||||
{
|
||||
public class DesignTimeRenameFileViewModel : ReactiveValidationObject, IRenameFileViewModel
|
||||
{
|
||||
public DesignTimeRenameFileViewModel() => this.ValidationRule(x => x.NewName, name => false, "Validation error.");
|
||||
public DesignTimeRenameFileViewModel() => this.ValidationRule(x => x.NewName, name => false, "Validation error.");
|
||||
|
||||
public bool IsLoading { get; }
|
||||
public bool IsLoading { get; }
|
||||
|
||||
public bool IsVisible { get; set; }
|
||||
public bool IsVisible { get; set; }
|
||||
|
||||
public string OldName { get; } = "file";
|
||||
public string OldName { get; } = "file";
|
||||
|
||||
public string NewName { get; set; }
|
||||
public string NewName { get; set; }
|
||||
|
||||
public bool HasErrorMessage { get; } = true;
|
||||
public bool HasErrorMessage { get; } = true;
|
||||
|
||||
public string ErrorMessage { get; } = "Error message example.";
|
||||
public string ErrorMessage { get; } = "Error message example.";
|
||||
|
||||
public ReactiveCommand<Unit, Unit> Rename { get; }
|
||||
public ReactiveCommand<Unit, Unit> Rename { get; }
|
||||
|
||||
public ReactiveCommand<Unit, Unit> Close { get; }
|
||||
public ReactiveCommand<Unit, Unit> Close { get; }
|
||||
|
||||
public ReactiveCommand<Unit, Unit> Open { get; }
|
||||
}
|
||||
public ReactiveCommand<Unit, Unit> Open { get; }
|
||||
}
|
|
@ -1,21 +1,20 @@
|
|||
using System;
|
||||
using System.Globalization;
|
||||
|
||||
namespace Camelotia.Presentation.Extensions
|
||||
{
|
||||
public static class ByteConversionExtensions
|
||||
{
|
||||
public static string ByteSizeToString(this long byteCount, int decimalPrecision = 1)
|
||||
{
|
||||
string[] suf = { "B", "KB", "MB", "GB", "TB", "PB", "EB" };
|
||||
if (byteCount == 0)
|
||||
return "0" + suf[0];
|
||||
namespace Camelotia.Presentation.Extensions;
|
||||
|
||||
var bytes = Math.Abs(byteCount);
|
||||
var place = Convert.ToInt32(Math.Floor(Math.Log(bytes, 1000)));
|
||||
var num = Math.Round(bytes / Math.Pow(1000, place), decimalPrecision);
|
||||
var digit = Math.Sign(byteCount) * num;
|
||||
return digit.ToString(CultureInfo.InvariantCulture) + suf[place];
|
||||
}
|
||||
public static class ByteConversionExtensions
|
||||
{
|
||||
public static string ByteSizeToString(this long byteCount, int decimalPrecision = 1)
|
||||
{
|
||||
string[] suf = { "B", "KB", "MB", "GB", "TB", "PB", "EB" };
|
||||
if (byteCount == 0)
|
||||
return "0" + suf[0];
|
||||
|
||||
var bytes = Math.Abs(byteCount);
|
||||
var place = Convert.ToInt32(Math.Floor(Math.Log(bytes, 1000)));
|
||||
var num = Math.Round(bytes / Math.Pow(1000, place), decimalPrecision);
|
||||
var digit = Math.Sign(byteCount) * num;
|
||||
return digit.ToString(CultureInfo.InvariantCulture) + suf[place];
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,24 +5,23 @@ using Newtonsoft.Json;
|
|||
using ReactiveUI;
|
||||
using Splat;
|
||||
|
||||
namespace Camelotia.Presentation.Infrastructure
|
||||
namespace Camelotia.Presentation.Infrastructure;
|
||||
|
||||
public class AkavacheSuspensionDriver<TAppState> : ISuspensionDriver
|
||||
where TAppState : class
|
||||
{
|
||||
public class AkavacheSuspensionDriver<TAppState> : ISuspensionDriver
|
||||
where TAppState : class
|
||||
private const string Key = "camelotia-state";
|
||||
|
||||
static AkavacheSuspensionDriver() => Locator.CurrentMutable.RegisterConstant(new JsonSerializerSettings
|
||||
{
|
||||
private const string Key = "camelotia-state";
|
||||
ObjectCreationHandling = ObjectCreationHandling.Replace
|
||||
});
|
||||
|
||||
static AkavacheSuspensionDriver() => Locator.CurrentMutable.RegisterConstant(new JsonSerializerSettings
|
||||
{
|
||||
ObjectCreationHandling = ObjectCreationHandling.Replace
|
||||
});
|
||||
public AkavacheSuspensionDriver(string appName = "CamelotiaV2") => BlobCache.ApplicationName = appName;
|
||||
|
||||
public AkavacheSuspensionDriver(string appName = "CamelotiaV2") => BlobCache.ApplicationName = appName;
|
||||
public IObservable<Unit> InvalidateState() => BlobCache.UserAccount.InvalidateObject<TAppState>(Key);
|
||||
|
||||
public IObservable<Unit> InvalidateState() => BlobCache.UserAccount.InvalidateObject<TAppState>(Key);
|
||||
public IObservable<object> LoadState() => BlobCache.UserAccount.GetObject<TAppState>(Key);
|
||||
|
||||
public IObservable<object> LoadState() => BlobCache.UserAccount.GetObject<TAppState>(Key);
|
||||
|
||||
public IObservable<Unit> SaveState(object state) => BlobCache.UserAccount.InsertObject(Key, (TAppState)state);
|
||||
}
|
||||
public IObservable<Unit> SaveState(object state) => BlobCache.UserAccount.InsertObject(Key, (TAppState)state);
|
||||
}
|
|
@ -6,45 +6,44 @@ using Newtonsoft.Json;
|
|||
using Newtonsoft.Json.Serialization;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace Camelotia.Presentation.Infrastructure
|
||||
namespace Camelotia.Presentation.Infrastructure;
|
||||
|
||||
public sealed class NewtonsoftJsonSuspensionDriver : ISuspensionDriver
|
||||
{
|
||||
public sealed class NewtonsoftJsonSuspensionDriver : ISuspensionDriver
|
||||
private readonly string _stateFilePath;
|
||||
private readonly JsonSerializerSettings _settings = new()
|
||||
{
|
||||
private readonly string _stateFilePath;
|
||||
private readonly JsonSerializerSettings _settings = new JsonSerializerSettings
|
||||
{
|
||||
TypeNameHandling = TypeNameHandling.All,
|
||||
NullValueHandling = NullValueHandling.Ignore,
|
||||
ObjectCreationHandling = ObjectCreationHandling.Replace,
|
||||
ContractResolver = new CamelCasePropertyNamesContractResolver(),
|
||||
};
|
||||
TypeNameHandling = TypeNameHandling.All,
|
||||
NullValueHandling = NullValueHandling.Ignore,
|
||||
ObjectCreationHandling = ObjectCreationHandling.Replace,
|
||||
ContractResolver = new CamelCasePropertyNamesContractResolver(),
|
||||
};
|
||||
|
||||
public NewtonsoftJsonSuspensionDriver(string stateFilePath) => _stateFilePath = stateFilePath;
|
||||
public NewtonsoftJsonSuspensionDriver(string stateFilePath) => _stateFilePath = stateFilePath;
|
||||
|
||||
public IObservable<Unit> InvalidateState()
|
||||
public IObservable<Unit> InvalidateState()
|
||||
{
|
||||
if (File.Exists(_stateFilePath))
|
||||
File.Delete(_stateFilePath);
|
||||
return Observable.Return(Unit.Default);
|
||||
}
|
||||
|
||||
public IObservable<object> LoadState()
|
||||
{
|
||||
if (!File.Exists(_stateFilePath))
|
||||
{
|
||||
if (File.Exists(_stateFilePath))
|
||||
File.Delete(_stateFilePath);
|
||||
return Observable.Return(Unit.Default);
|
||||
return Observable.Throw<object>(new FileNotFoundException(_stateFilePath));
|
||||
}
|
||||
|
||||
public IObservable<object> LoadState()
|
||||
{
|
||||
if (!File.Exists(_stateFilePath))
|
||||
{
|
||||
return Observable.Throw<object>(new FileNotFoundException(_stateFilePath));
|
||||
}
|
||||
var lines = File.ReadAllText(_stateFilePath);
|
||||
var state = JsonConvert.DeserializeObject<object>(lines, _settings);
|
||||
return Observable.Return(state);
|
||||
}
|
||||
|
||||
var lines = File.ReadAllText(_stateFilePath);
|
||||
var state = JsonConvert.DeserializeObject<object>(lines, _settings);
|
||||
return Observable.Return(state);
|
||||
}
|
||||
|
||||
public IObservable<Unit> SaveState(object state)
|
||||
{
|
||||
var lines = JsonConvert.SerializeObject(state, Formatting.Indented, _settings);
|
||||
File.WriteAllText(_stateFilePath, lines);
|
||||
return Observable.Return(Unit.Default);
|
||||
}
|
||||
public IObservable<Unit> SaveState(object state)
|
||||
{
|
||||
var lines = JsonConvert.SerializeObject(state, Formatting.Indented, _settings);
|
||||
File.WriteAllText(_stateFilePath, lines);
|
||||
return Observable.Return(Unit.Default);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,23 +1,22 @@
|
|||
using System.ComponentModel;
|
||||
|
||||
namespace Camelotia.Presentation.Interfaces
|
||||
namespace Camelotia.Presentation.Interfaces;
|
||||
|
||||
public interface IAuthViewModel : INotifyPropertyChanged
|
||||
{
|
||||
public interface IAuthViewModel : INotifyPropertyChanged
|
||||
{
|
||||
IDirectAuthViewModel DirectAuth { get; }
|
||||
IDirectAuthViewModel DirectAuth { get; }
|
||||
|
||||
IHostAuthViewModel HostAuth { get; }
|
||||
IHostAuthViewModel HostAuth { get; }
|
||||
|
||||
IOAuthViewModel OAuth { get; }
|
||||
IOAuthViewModel OAuth { get; }
|
||||
|
||||
bool SupportsDirectAuth { get; }
|
||||
bool SupportsDirectAuth { get; }
|
||||
|
||||
bool SupportsHostAuth { get; }
|
||||
bool SupportsHostAuth { get; }
|
||||
|
||||
bool SupportsOAuth { get; }
|
||||
bool SupportsOAuth { get; }
|
||||
|
||||
bool IsAuthenticated { get; }
|
||||
bool IsAuthenticated { get; }
|
||||
|
||||
bool IsAnonymous { get; }
|
||||
}
|
||||
bool IsAnonymous { get; }
|
||||
}
|
|
@ -5,68 +5,67 @@ using System.Reactive;
|
|||
using Camelotia.Services.Models;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace Camelotia.Presentation.Interfaces
|
||||
namespace Camelotia.Presentation.Interfaces;
|
||||
|
||||
public interface ICloudViewModel : INotifyPropertyChanged
|
||||
{
|
||||
public interface ICloudViewModel : INotifyPropertyChanged
|
||||
{
|
||||
Guid Id { get; }
|
||||
Guid Id { get; }
|
||||
|
||||
IAuthViewModel Auth { get; }
|
||||
IAuthViewModel Auth { get; }
|
||||
|
||||
IRenameFileViewModel Rename { get; }
|
||||
IRenameFileViewModel Rename { get; }
|
||||
|
||||
ICreateFolderViewModel Folder { get; }
|
||||
ICreateFolderViewModel Folder { get; }
|
||||
|
||||
IFileViewModel SelectedFile { get; set; }
|
||||
IFileViewModel SelectedFile { get; set; }
|
||||
|
||||
IEnumerable<IFileViewModel> Files { get; }
|
||||
IEnumerable<IFileViewModel> Files { get; }
|
||||
|
||||
IEnumerable<IFolderViewModel> BreadCrumbs { get; }
|
||||
IEnumerable<IFolderViewModel> BreadCrumbs { get; }
|
||||
|
||||
ReactiveCommand<Unit, Unit> DownloadSelectedFile { get; }
|
||||
ReactiveCommand<Unit, Unit> DownloadSelectedFile { get; }
|
||||
|
||||
ReactiveCommand<Unit, Unit> UploadToCurrentPath { get; }
|
||||
ReactiveCommand<Unit, Unit> UploadToCurrentPath { get; }
|
||||
|
||||
ReactiveCommand<Unit, Unit> DeleteSelectedFile { get; }
|
||||
ReactiveCommand<Unit, Unit> DeleteSelectedFile { get; }
|
||||
|
||||
ReactiveCommand<Unit, Unit> UnselectFile { get; }
|
||||
ReactiveCommand<Unit, Unit> UnselectFile { get; }
|
||||
|
||||
ReactiveCommand<Unit, IEnumerable<FileModel>> Refresh { get; }
|
||||
ReactiveCommand<Unit, IEnumerable<FileModel>> Refresh { get; }
|
||||
|
||||
ReactiveCommand<Unit, Unit> Logout { get; }
|
||||
ReactiveCommand<Unit, Unit> Logout { get; }
|
||||
|
||||
ReactiveCommand<Unit, string> Back { get; }
|
||||
ReactiveCommand<Unit, string> Back { get; }
|
||||
|
||||
ReactiveCommand<Unit, string> Open { get; }
|
||||
ReactiveCommand<Unit, string> Open { get; }
|
||||
|
||||
ReactiveCommand<string, string> SetPath { get; }
|
||||
ReactiveCommand<string, string> SetPath { get; }
|
||||
|
||||
bool IsCurrentPathEmpty { get; }
|
||||
bool IsCurrentPathEmpty { get; }
|
||||
|
||||
bool IsLoading { get; }
|
||||
bool IsLoading { get; }
|
||||
|
||||
bool IsReady { get; }
|
||||
bool IsReady { get; }
|
||||
|
||||
bool HasErrorMessage { get; }
|
||||
bool HasErrorMessage { get; }
|
||||
|
||||
bool CanLogout { get; }
|
||||
bool CanLogout { get; }
|
||||
|
||||
bool CanInteract { get; }
|
||||
bool CanInteract { get; }
|
||||
|
||||
bool ShowBreadCrumbs { get; }
|
||||
bool ShowBreadCrumbs { get; }
|
||||
|
||||
bool HideBreadCrumbs { get; }
|
||||
bool HideBreadCrumbs { get; }
|
||||
|
||||
int RefreshingIn { get; }
|
||||
int RefreshingIn { get; }
|
||||
|
||||
string CurrentPath { get; }
|
||||
string CurrentPath { get; }
|
||||
|
||||
string Description { get; }
|
||||
string Description { get; }
|
||||
|
||||
DateTime Created { get; }
|
||||
DateTime Created { get; }
|
||||
|
||||
string Name { get; }
|
||||
string Name { get; }
|
||||
|
||||
string Size { get; }
|
||||
}
|
||||
string Size { get; }
|
||||
}
|
|
@ -3,30 +3,29 @@ using System.Reactive;
|
|||
using ReactiveUI;
|
||||
using ReactiveUI.Validation.Abstractions;
|
||||
|
||||
namespace Camelotia.Presentation.Interfaces
|
||||
namespace Camelotia.Presentation.Interfaces;
|
||||
|
||||
public interface ICreateFolderViewModel :
|
||||
INotifyPropertyChanged,
|
||||
INotifyDataErrorInfo,
|
||||
IValidatableViewModel,
|
||||
IReactiveObject
|
||||
{
|
||||
public interface ICreateFolderViewModel :
|
||||
INotifyPropertyChanged,
|
||||
INotifyDataErrorInfo,
|
||||
IValidatableViewModel,
|
||||
IReactiveObject
|
||||
{
|
||||
bool IsLoading { get; }
|
||||
bool IsLoading { get; }
|
||||
|
||||
bool IsVisible { get; set; }
|
||||
bool IsVisible { get; set; }
|
||||
|
||||
string Name { get; set; }
|
||||
string Name { get; set; }
|
||||
|
||||
string Path { get; }
|
||||
string Path { get; }
|
||||
|
||||
bool HasErrorMessage { get; }
|
||||
bool HasErrorMessage { get; }
|
||||
|
||||
string ErrorMessage { get; }
|
||||
string ErrorMessage { get; }
|
||||
|
||||
ReactiveCommand<Unit, Unit> Create { get; }
|
||||
ReactiveCommand<Unit, Unit> Create { get; }
|
||||
|
||||
ReactiveCommand<Unit, Unit> Close { get; }
|
||||
ReactiveCommand<Unit, Unit> Close { get; }
|
||||
|
||||
ReactiveCommand<Unit, Unit> Open { get; }
|
||||
}
|
||||
ReactiveCommand<Unit, Unit> Open { get; }
|
||||
}
|
|
@ -3,24 +3,23 @@ using System.Reactive;
|
|||
using ReactiveUI;
|
||||
using ReactiveUI.Validation.Abstractions;
|
||||
|
||||
namespace Camelotia.Presentation.Interfaces
|
||||
namespace Camelotia.Presentation.Interfaces;
|
||||
|
||||
public interface IDirectAuthViewModel :
|
||||
INotifyPropertyChanged,
|
||||
INotifyDataErrorInfo,
|
||||
IValidatableViewModel,
|
||||
IReactiveObject
|
||||
{
|
||||
public interface IDirectAuthViewModel :
|
||||
INotifyPropertyChanged,
|
||||
INotifyDataErrorInfo,
|
||||
IValidatableViewModel,
|
||||
IReactiveObject
|
||||
{
|
||||
string Username { get; set; }
|
||||
string Username { get; set; }
|
||||
|
||||
string Password { get; set; }
|
||||
string Password { get; set; }
|
||||
|
||||
ReactiveCommand<Unit, Unit> Login { get; }
|
||||
ReactiveCommand<Unit, Unit> Login { get; }
|
||||
|
||||
bool HasErrorMessage { get; }
|
||||
bool HasErrorMessage { get; }
|
||||
|
||||
string ErrorMessage { get; }
|
||||
string ErrorMessage { get; }
|
||||
|
||||
bool IsBusy { get; }
|
||||
}
|
||||
bool IsBusy { get; }
|
||||
}
|
|
@ -1,21 +1,20 @@
|
|||
using System.ComponentModel;
|
||||
|
||||
namespace Camelotia.Presentation.Interfaces
|
||||
namespace Camelotia.Presentation.Interfaces;
|
||||
|
||||
public interface IFileViewModel : INotifyPropertyChanged
|
||||
{
|
||||
public interface IFileViewModel : INotifyPropertyChanged
|
||||
{
|
||||
string Name { get; }
|
||||
string Name { get; }
|
||||
|
||||
ICloudViewModel Provider { get; }
|
||||
ICloudViewModel Provider { get; }
|
||||
|
||||
string Modified { get; }
|
||||
string Modified { get; }
|
||||
|
||||
bool IsFolder { get; }
|
||||
bool IsFolder { get; }
|
||||
|
||||
bool IsFile { get; }
|
||||
bool IsFile { get; }
|
||||
|
||||
string Path { get; }
|
||||
string Path { get; }
|
||||
|
||||
string Size { get; }
|
||||
}
|
||||
}
|
||||
string Size { get; }
|
||||
}
|
|
@ -1,14 +1,13 @@
|
|||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace Camelotia.Presentation.Interfaces
|
||||
namespace Camelotia.Presentation.Interfaces;
|
||||
|
||||
public interface IFolderViewModel : INotifyPropertyChanged
|
||||
{
|
||||
public interface IFolderViewModel : INotifyPropertyChanged
|
||||
{
|
||||
string Name { get; }
|
||||
string Name { get; }
|
||||
|
||||
string FullPath { get; }
|
||||
string FullPath { get; }
|
||||
|
||||
IEnumerable<IFolderViewModel> Children { get; }
|
||||
}
|
||||
}
|
||||
IEnumerable<IFolderViewModel> Children { get; }
|
||||
}
|
|
@ -1,15 +1,14 @@
|
|||
using ReactiveUI;
|
||||
using ReactiveUI.Validation.Abstractions;
|
||||
|
||||
namespace Camelotia.Presentation.Interfaces
|
||||
{
|
||||
public interface IHostAuthViewModel :
|
||||
IDirectAuthViewModel,
|
||||
IValidatableViewModel,
|
||||
IReactiveObject
|
||||
{
|
||||
string Address { get; set; }
|
||||
namespace Camelotia.Presentation.Interfaces;
|
||||
|
||||
string Port { get; set; }
|
||||
}
|
||||
public interface IHostAuthViewModel :
|
||||
IDirectAuthViewModel,
|
||||
IValidatableViewModel,
|
||||
IReactiveObject
|
||||
{
|
||||
string Address { get; set; }
|
||||
|
||||
string Port { get; set; }
|
||||
}
|
|
@ -5,32 +5,31 @@ using System.Reactive;
|
|||
using Camelotia.Services.Models;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace Camelotia.Presentation.Interfaces
|
||||
namespace Camelotia.Presentation.Interfaces;
|
||||
|
||||
public interface IMainViewModel : INotifyPropertyChanged
|
||||
{
|
||||
public interface IMainViewModel : INotifyPropertyChanged
|
||||
{
|
||||
ReadOnlyObservableCollection<ICloudViewModel> Clouds { get; }
|
||||
ReadOnlyObservableCollection<ICloudViewModel> Clouds { get; }
|
||||
|
||||
ICloudViewModel SelectedProvider { get; set; }
|
||||
ICloudViewModel SelectedProvider { get; set; }
|
||||
|
||||
IEnumerable<CloudType> SupportedTypes { get; }
|
||||
IEnumerable<CloudType> SupportedTypes { get; }
|
||||
|
||||
CloudType SelectedSupportedType { get; set; }
|
||||
CloudType SelectedSupportedType { get; set; }
|
||||
|
||||
bool WelcomeScreenCollapsed { get; }
|
||||
bool WelcomeScreenCollapsed { get; }
|
||||
|
||||
bool WelcomeScreenVisible { get; }
|
||||
bool WelcomeScreenVisible { get; }
|
||||
|
||||
ReactiveCommand<Unit, Unit> Unselect { get; }
|
||||
ReactiveCommand<Unit, Unit> Unselect { get; }
|
||||
|
||||
ReactiveCommand<Unit, Unit> Refresh { get; }
|
||||
ReactiveCommand<Unit, Unit> Refresh { get; }
|
||||
|
||||
ReactiveCommand<Unit, Unit> Remove { get; }
|
||||
ReactiveCommand<Unit, Unit> Remove { get; }
|
||||
|
||||
ReactiveCommand<Unit, Unit> Add { get; }
|
||||
ReactiveCommand<Unit, Unit> Add { get; }
|
||||
|
||||
bool IsLoading { get; }
|
||||
bool IsLoading { get; }
|
||||
|
||||
bool IsReady { get; }
|
||||
}
|
||||
bool IsReady { get; }
|
||||
}
|
|
@ -2,16 +2,15 @@ using System.ComponentModel;
|
|||
using System.Reactive;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace Camelotia.Presentation.Interfaces
|
||||
namespace Camelotia.Presentation.Interfaces;
|
||||
|
||||
public interface IOAuthViewModel : INotifyPropertyChanged
|
||||
{
|
||||
public interface IOAuthViewModel : INotifyPropertyChanged
|
||||
{
|
||||
ReactiveCommand<Unit, Unit> Login { get; }
|
||||
ReactiveCommand<Unit, Unit> Login { get; }
|
||||
|
||||
bool HasErrorMessage { get; }
|
||||
bool HasErrorMessage { get; }
|
||||
|
||||
string ErrorMessage { get; }
|
||||
string ErrorMessage { get; }
|
||||
|
||||
bool IsBusy { get; }
|
||||
}
|
||||
bool IsBusy { get; }
|
||||
}
|
|
@ -3,30 +3,29 @@ using System.Reactive;
|
|||
using ReactiveUI;
|
||||
using ReactiveUI.Validation.Abstractions;
|
||||
|
||||
namespace Camelotia.Presentation.Interfaces
|
||||
namespace Camelotia.Presentation.Interfaces;
|
||||
|
||||
public interface IRenameFileViewModel :
|
||||
INotifyPropertyChanged,
|
||||
INotifyDataErrorInfo,
|
||||
IValidatableViewModel,
|
||||
IReactiveObject
|
||||
{
|
||||
public interface IRenameFileViewModel :
|
||||
INotifyPropertyChanged,
|
||||
INotifyDataErrorInfo,
|
||||
IValidatableViewModel,
|
||||
IReactiveObject
|
||||
{
|
||||
bool IsLoading { get; }
|
||||
bool IsLoading { get; }
|
||||
|
||||
bool IsVisible { get; set; }
|
||||
bool IsVisible { get; set; }
|
||||
|
||||
string OldName { get; }
|
||||
string OldName { get; }
|
||||
|
||||
string NewName { get; set; }
|
||||
string NewName { get; set; }
|
||||
|
||||
bool HasErrorMessage { get; }
|
||||
bool HasErrorMessage { get; }
|
||||
|
||||
string ErrorMessage { get; }
|
||||
string ErrorMessage { get; }
|
||||
|
||||
ReactiveCommand<Unit, Unit> Rename { get; }
|
||||
ReactiveCommand<Unit, Unit> Rename { get; }
|
||||
|
||||
ReactiveCommand<Unit, Unit> Close { get; }
|
||||
ReactiveCommand<Unit, Unit> Close { get; }
|
||||
|
||||
ReactiveCommand<Unit, Unit> Open { get; }
|
||||
}
|
||||
ReactiveCommand<Unit, Unit> Open { get; }
|
||||
}
|
|
@ -3,52 +3,51 @@ using Camelotia.Presentation.Interfaces;
|
|||
using Camelotia.Services.Interfaces;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace Camelotia.Presentation.ViewModels
|
||||
namespace Camelotia.Presentation.ViewModels;
|
||||
|
||||
public sealed class AuthViewModel : ReactiveObject, IAuthViewModel
|
||||
{
|
||||
public sealed class AuthViewModel : ReactiveObject, IAuthViewModel
|
||||
private readonly ObservableAsPropertyHelper<bool> _isAuthenticated;
|
||||
private readonly ObservableAsPropertyHelper<bool> _isAnonymous;
|
||||
private readonly ICloud _provider;
|
||||
|
||||
public AuthViewModel(
|
||||
IDirectAuthViewModel direct,
|
||||
IHostAuthViewModel host,
|
||||
IOAuthViewModel open,
|
||||
ICloud provider)
|
||||
{
|
||||
private readonly ObservableAsPropertyHelper<bool> _isAuthenticated;
|
||||
private readonly ObservableAsPropertyHelper<bool> _isAnonymous;
|
||||
private readonly ICloud _provider;
|
||||
OAuth = open;
|
||||
HostAuth = host;
|
||||
DirectAuth = direct;
|
||||
_provider = provider;
|
||||
|
||||
public AuthViewModel(
|
||||
IDirectAuthViewModel direct,
|
||||
IHostAuthViewModel host,
|
||||
IOAuthViewModel open,
|
||||
ICloud provider)
|
||||
{
|
||||
OAuth = open;
|
||||
HostAuth = host;
|
||||
DirectAuth = direct;
|
||||
_provider = provider;
|
||||
_isAuthenticated = _provider
|
||||
.IsAuthorized
|
||||
.DistinctUntilChanged()
|
||||
.Log(this, $"Authentication state changed for {provider.Name}")
|
||||
.ObserveOn(RxApp.MainThreadScheduler)
|
||||
.ToProperty(this, x => x.IsAuthenticated);
|
||||
|
||||
_isAuthenticated = _provider
|
||||
.IsAuthorized
|
||||
.DistinctUntilChanged()
|
||||
.Log(this, $"Authentication state changed for {provider.Name}")
|
||||
.ObserveOn(RxApp.MainThreadScheduler)
|
||||
.ToProperty(this, x => x.IsAuthenticated);
|
||||
|
||||
_isAnonymous = this
|
||||
.WhenAnyValue(x => x.IsAuthenticated)
|
||||
.Select(authenticated => !authenticated)
|
||||
.ToProperty(this, x => x.IsAnonymous);
|
||||
}
|
||||
|
||||
public bool IsAnonymous => _isAnonymous.Value;
|
||||
|
||||
public bool IsAuthenticated => _isAuthenticated.Value;
|
||||
|
||||
public bool SupportsDirectAuth => _provider.SupportsDirectAuth;
|
||||
|
||||
public bool SupportsHostAuth => _provider.SupportsHostAuth;
|
||||
|
||||
public bool SupportsOAuth => _provider.SupportsOAuth;
|
||||
|
||||
public IDirectAuthViewModel DirectAuth { get; }
|
||||
|
||||
public IHostAuthViewModel HostAuth { get; }
|
||||
|
||||
public IOAuthViewModel OAuth { get; }
|
||||
_isAnonymous = this
|
||||
.WhenAnyValue(x => x.IsAuthenticated)
|
||||
.Select(authenticated => !authenticated)
|
||||
.ToProperty(this, x => x.IsAnonymous);
|
||||
}
|
||||
|
||||
public bool IsAnonymous => _isAnonymous.Value;
|
||||
|
||||
public bool IsAuthenticated => _isAuthenticated.Value;
|
||||
|
||||
public bool SupportsDirectAuth => _provider.SupportsDirectAuth;
|
||||
|
||||
public bool SupportsHostAuth => _provider.SupportsHostAuth;
|
||||
|
||||
public bool SupportsOAuth => _provider.SupportsOAuth;
|
||||
|
||||
public IDirectAuthViewModel DirectAuth { get; }
|
||||
|
||||
public IHostAuthViewModel HostAuth { get; }
|
||||
|
||||
public IOAuthViewModel OAuth { get; }
|
||||
}
|
|
@ -14,340 +14,339 @@ using Camelotia.Services.Models;
|
|||
using ReactiveUI;
|
||||
using ReactiveUI.Fody.Helpers;
|
||||
|
||||
namespace Camelotia.Presentation.ViewModels
|
||||
namespace Camelotia.Presentation.ViewModels;
|
||||
|
||||
public delegate ICloudViewModel CloudViewModelFactory(CloudState state, ICloud provider);
|
||||
|
||||
public sealed class CloudViewModel : ReactiveObject, ICloudViewModel, IActivatableViewModel
|
||||
{
|
||||
public delegate ICloudViewModel CloudViewModelFactory(CloudState state, ICloud provider);
|
||||
private readonly ObservableAsPropertyHelper<IEnumerable<IFolderViewModel>> _breadCrumbs;
|
||||
private readonly ObservableAsPropertyHelper<IEnumerable<IFileViewModel>> _files;
|
||||
private readonly ObservableAsPropertyHelper<bool> _isCurrentPathEmpty;
|
||||
private readonly ObservableAsPropertyHelper<bool> _showBreadCrumbs;
|
||||
private readonly ObservableAsPropertyHelper<bool> _hasErrorMessage;
|
||||
private readonly ObservableAsPropertyHelper<bool> _hideBreadCrumbs;
|
||||
private readonly ObservableAsPropertyHelper<string> _currentPath;
|
||||
private readonly ObservableAsPropertyHelper<bool> _canInteract;
|
||||
private readonly ObservableAsPropertyHelper<bool> _isLoading;
|
||||
private readonly ObservableAsPropertyHelper<bool> _canLogout;
|
||||
private readonly ObservableAsPropertyHelper<bool> _isReady;
|
||||
private readonly ICloud _cloud;
|
||||
|
||||
public sealed class CloudViewModel : ReactiveObject, ICloudViewModel, IActivatableViewModel
|
||||
public CloudViewModel(
|
||||
CloudState state,
|
||||
CreateFolderViewModelFactory createFolderFactory,
|
||||
RenameFileViewModelFactory renameFactory,
|
||||
FileViewModelFactory fileFactory,
|
||||
FolderViewModelFactory folderFactory,
|
||||
IAuthViewModel auth,
|
||||
IFileManager files,
|
||||
ICloud cloud)
|
||||
{
|
||||
private readonly ObservableAsPropertyHelper<IEnumerable<IFolderViewModel>> _breadCrumbs;
|
||||
private readonly ObservableAsPropertyHelper<IEnumerable<IFileViewModel>> _files;
|
||||
private readonly ObservableAsPropertyHelper<bool> _isCurrentPathEmpty;
|
||||
private readonly ObservableAsPropertyHelper<bool> _showBreadCrumbs;
|
||||
private readonly ObservableAsPropertyHelper<bool> _hasErrorMessage;
|
||||
private readonly ObservableAsPropertyHelper<bool> _hideBreadCrumbs;
|
||||
private readonly ObservableAsPropertyHelper<string> _currentPath;
|
||||
private readonly ObservableAsPropertyHelper<bool> _canInteract;
|
||||
private readonly ObservableAsPropertyHelper<bool> _isLoading;
|
||||
private readonly ObservableAsPropertyHelper<bool> _canLogout;
|
||||
private readonly ObservableAsPropertyHelper<bool> _isReady;
|
||||
private readonly ICloud _cloud;
|
||||
|
||||
public CloudViewModel(
|
||||
CloudState state,
|
||||
CreateFolderViewModelFactory createFolderFactory,
|
||||
RenameFileViewModelFactory renameFactory,
|
||||
FileViewModelFactory fileFactory,
|
||||
FolderViewModelFactory folderFactory,
|
||||
IAuthViewModel auth,
|
||||
IFileManager files,
|
||||
ICloud cloud)
|
||||
{
|
||||
_cloud = cloud;
|
||||
Folder = createFolderFactory(this);
|
||||
Rename = renameFactory(this);
|
||||
Auth = auth;
|
||||
|
||||
var canInteract = this
|
||||
.WhenAnyValue(
|
||||
x => x.Folder.IsVisible,
|
||||
x => x.Rename.IsVisible,
|
||||
(folder, rename) => !folder && !rename);
|
||||
|
||||
_canInteract = canInteract
|
||||
.ToProperty(this, x => x.CanInteract);
|
||||
|
||||
var canRefresh = this
|
||||
.WhenAnyValue(
|
||||
x => x.Folder.IsVisible,
|
||||
x => x.Rename.IsVisible,
|
||||
x => x.Auth.IsAuthenticated,
|
||||
(folder, rename, authenticated) => !folder && !rename && authenticated);
|
||||
|
||||
Refresh = ReactiveCommand.CreateFromTask(
|
||||
() => cloud.GetFiles(CurrentPath),
|
||||
canRefresh);
|
||||
|
||||
_files = Refresh
|
||||
.Select(
|
||||
items => items
|
||||
.Select(file => fileFactory(file, this))
|
||||
.OrderByDescending(file => file.IsFolder)
|
||||
.ThenBy(file => file.Name)
|
||||
.ToList())
|
||||
.Where(items => Files == null || !items.SequenceEqual(Files))
|
||||
.ToProperty(this, x => x.Files);
|
||||
|
||||
_isLoading = Refresh
|
||||
.IsExecuting
|
||||
.ToProperty(this, x => x.IsLoading);
|
||||
|
||||
_isReady = Refresh
|
||||
.IsExecuting
|
||||
.Skip(1)
|
||||
.Select(executing => !executing)
|
||||
.ToProperty(this, x => x.IsReady);
|
||||
|
||||
var canOpenCurrentPath = this
|
||||
.WhenAnyValue(x => x.SelectedFile)
|
||||
.Select(file => file != null && file.IsFolder)
|
||||
.CombineLatest(Refresh.IsExecuting, canInteract, (folder, busy, ci) => folder && ci && !busy);
|
||||
|
||||
Open = ReactiveCommand.Create(
|
||||
() => Path.Combine(CurrentPath, SelectedFile.Name),
|
||||
canOpenCurrentPath);
|
||||
|
||||
var canCurrentPathGoBack = this
|
||||
.WhenAnyValue(x => x.CurrentPath)
|
||||
.Where(path => path != null)
|
||||
.Select(path => path.Length > cloud.InitialPath.Length)
|
||||
.CombineLatest(Refresh.IsExecuting, canInteract, (valid, busy, ci) => valid && ci && !busy);
|
||||
|
||||
Back = ReactiveCommand.Create(
|
||||
() => Path.GetDirectoryName(CurrentPath),
|
||||
canCurrentPathGoBack);
|
||||
|
||||
SetPath = ReactiveCommand.Create<string, string>(path => path);
|
||||
|
||||
_currentPath = Open
|
||||
.Merge(Back)
|
||||
.Merge(SetPath)
|
||||
.Select(path => path ?? cloud.InitialPath)
|
||||
.DistinctUntilChanged()
|
||||
.Log(this, $"Current path changed in {cloud.Name}")
|
||||
.ToProperty(this, x => x.CurrentPath, state.CurrentPath ?? cloud.InitialPath);
|
||||
|
||||
var getBreadCrumbs = ReactiveCommand.CreateFromTask(
|
||||
() => cloud.GetBreadCrumbs(CurrentPath));
|
||||
|
||||
_breadCrumbs = getBreadCrumbs
|
||||
.Where(items => items != null && items.Any())
|
||||
.Select(items => items.Select(folder => folderFactory(folder, this)))
|
||||
.ToProperty(this, x => x.BreadCrumbs);
|
||||
|
||||
_showBreadCrumbs = getBreadCrumbs
|
||||
.ThrownExceptions
|
||||
.Select(exception => false)
|
||||
.Merge(getBreadCrumbs.Select(items => items != null && items.Any()))
|
||||
.ObserveOn(RxApp.MainThreadScheduler)
|
||||
.ToProperty(this, x => x.ShowBreadCrumbs);
|
||||
|
||||
_hideBreadCrumbs = this
|
||||
.WhenAnyValue(x => x.ShowBreadCrumbs)
|
||||
.Select(show => !show)
|
||||
.ToProperty(this, x => x.HideBreadCrumbs);
|
||||
|
||||
this.WhenAnyValue(x => x.CurrentPath, x => x.IsReady)
|
||||
.Where(x => x.Item1 != null && x.Item2)
|
||||
.Select(_ => Unit.Default)
|
||||
.InvokeCommand(getBreadCrumbs);
|
||||
|
||||
this.WhenAnyValue(x => x.CurrentPath)
|
||||
.Skip(1)
|
||||
.Select(_ => Unit.Default)
|
||||
.InvokeCommand(Refresh);
|
||||
|
||||
this.WhenAnyValue(x => x.CurrentPath)
|
||||
.Subscribe(_ => SelectedFile = null);
|
||||
|
||||
_isCurrentPathEmpty = this
|
||||
.WhenAnyValue(x => x.Files)
|
||||
.Skip(1)
|
||||
.Where(items => items != null)
|
||||
.Select(items => !items.Any())
|
||||
.ToProperty(this, x => x.IsCurrentPathEmpty);
|
||||
|
||||
_hasErrorMessage = Refresh
|
||||
.ThrownExceptions
|
||||
.Select(exception => true)
|
||||
.ObserveOn(RxApp.MainThreadScheduler)
|
||||
.Merge(Refresh.Select(x => false))
|
||||
.ToProperty(this, x => x.HasErrorMessage);
|
||||
|
||||
var canUploadToCurrentPath = this
|
||||
.WhenAnyValue(x => x.CurrentPath)
|
||||
.Select(path => path != null)
|
||||
.CombineLatest(Refresh.IsExecuting, canInteract, (up, loading, can) => up && can && !loading);
|
||||
|
||||
UploadToCurrentPath = ReactiveCommand.CreateFromObservable(
|
||||
() => Observable
|
||||
.FromAsync(files.OpenRead)
|
||||
.Where(response => response.Name != null && response.Stream != null)
|
||||
.Select(args => _cloud.UploadFile(CurrentPath, args.Stream, args.Name))
|
||||
.SelectMany(task => task.ToObservable()),
|
||||
canUploadToCurrentPath);
|
||||
|
||||
UploadToCurrentPath.InvokeCommand(Refresh);
|
||||
|
||||
var canDownloadSelectedFile = this
|
||||
.WhenAnyValue(x => x.SelectedFile)
|
||||
.Select(file => file != null && !file.IsFolder)
|
||||
.CombineLatest(Refresh.IsExecuting, canInteract, (down, loading, can) => down && !loading && can);
|
||||
_cloud = cloud;
|
||||
Folder = createFolderFactory(this);
|
||||
Rename = renameFactory(this);
|
||||
Auth = auth;
|
||||
|
||||
var canInteract = this
|
||||
.WhenAnyValue(
|
||||
x => x.Folder.IsVisible,
|
||||
x => x.Rename.IsVisible,
|
||||
(folder, rename) => !folder && !rename);
|
||||
|
||||
_canInteract = canInteract
|
||||
.ToProperty(this, x => x.CanInteract);
|
||||
|
||||
var canRefresh = this
|
||||
.WhenAnyValue(
|
||||
x => x.Folder.IsVisible,
|
||||
x => x.Rename.IsVisible,
|
||||
x => x.Auth.IsAuthenticated,
|
||||
(folder, rename, authenticated) => !folder && !rename && authenticated);
|
||||
|
||||
Refresh = ReactiveCommand.CreateFromTask(
|
||||
() => cloud.GetFiles(CurrentPath),
|
||||
canRefresh);
|
||||
|
||||
_files = Refresh
|
||||
.Select(
|
||||
items => items
|
||||
.Select(file => fileFactory(file, this))
|
||||
.OrderByDescending(file => file.IsFolder)
|
||||
.ThenBy(file => file.Name)
|
||||
.ToList())
|
||||
.Where(items => Files == null || !items.SequenceEqual(Files))
|
||||
.ToProperty(this, x => x.Files);
|
||||
|
||||
_isLoading = Refresh
|
||||
.IsExecuting
|
||||
.ToProperty(this, x => x.IsLoading);
|
||||
|
||||
_isReady = Refresh
|
||||
.IsExecuting
|
||||
.Skip(1)
|
||||
.Select(executing => !executing)
|
||||
.ToProperty(this, x => x.IsReady);
|
||||
|
||||
var canOpenCurrentPath = this
|
||||
.WhenAnyValue(x => x.SelectedFile)
|
||||
.Select(file => file != null && file.IsFolder)
|
||||
.CombineLatest(Refresh.IsExecuting, canInteract, (folder, busy, ci) => folder && ci && !busy);
|
||||
|
||||
Open = ReactiveCommand.Create(
|
||||
() => Path.Combine(CurrentPath, SelectedFile.Name),
|
||||
canOpenCurrentPath);
|
||||
|
||||
var canCurrentPathGoBack = this
|
||||
.WhenAnyValue(x => x.CurrentPath)
|
||||
.Where(path => path != null)
|
||||
.Select(path => path.Length > cloud.InitialPath.Length)
|
||||
.CombineLatest(Refresh.IsExecuting, canInteract, (valid, busy, ci) => valid && ci && !busy);
|
||||
|
||||
Back = ReactiveCommand.Create(
|
||||
() => Path.GetDirectoryName(CurrentPath),
|
||||
canCurrentPathGoBack);
|
||||
|
||||
SetPath = ReactiveCommand.Create<string, string>(path => path);
|
||||
|
||||
_currentPath = Open
|
||||
.Merge(Back)
|
||||
.Merge(SetPath)
|
||||
.Select(path => path ?? cloud.InitialPath)
|
||||
.DistinctUntilChanged()
|
||||
.Log(this, $"Current path changed in {cloud.Name}")
|
||||
.ToProperty(this, x => x.CurrentPath, state.CurrentPath ?? cloud.InitialPath);
|
||||
|
||||
var getBreadCrumbs = ReactiveCommand.CreateFromTask(
|
||||
() => cloud.GetBreadCrumbs(CurrentPath));
|
||||
|
||||
_breadCrumbs = getBreadCrumbs
|
||||
.Where(items => items != null && items.Any())
|
||||
.Select(items => items.Select(folder => folderFactory(folder, this)))
|
||||
.ToProperty(this, x => x.BreadCrumbs);
|
||||
|
||||
_showBreadCrumbs = getBreadCrumbs
|
||||
.ThrownExceptions
|
||||
.Select(exception => false)
|
||||
.Merge(getBreadCrumbs.Select(items => items != null && items.Any()))
|
||||
.ObserveOn(RxApp.MainThreadScheduler)
|
||||
.ToProperty(this, x => x.ShowBreadCrumbs);
|
||||
|
||||
_hideBreadCrumbs = this
|
||||
.WhenAnyValue(x => x.ShowBreadCrumbs)
|
||||
.Select(show => !show)
|
||||
.ToProperty(this, x => x.HideBreadCrumbs);
|
||||
|
||||
this.WhenAnyValue(x => x.CurrentPath, x => x.IsReady)
|
||||
.Where(x => x.Item1 != null && x.Item2)
|
||||
.Select(_ => Unit.Default)
|
||||
.InvokeCommand(getBreadCrumbs);
|
||||
|
||||
this.WhenAnyValue(x => x.CurrentPath)
|
||||
.Skip(1)
|
||||
.Select(_ => Unit.Default)
|
||||
.InvokeCommand(Refresh);
|
||||
|
||||
this.WhenAnyValue(x => x.CurrentPath)
|
||||
.Subscribe(_ => SelectedFile = null);
|
||||
|
||||
_isCurrentPathEmpty = this
|
||||
.WhenAnyValue(x => x.Files)
|
||||
.Skip(1)
|
||||
.Where(items => items != null)
|
||||
.Select(items => !items.Any())
|
||||
.ToProperty(this, x => x.IsCurrentPathEmpty);
|
||||
|
||||
_hasErrorMessage = Refresh
|
||||
.ThrownExceptions
|
||||
.Select(exception => true)
|
||||
.ObserveOn(RxApp.MainThreadScheduler)
|
||||
.Merge(Refresh.Select(x => false))
|
||||
.ToProperty(this, x => x.HasErrorMessage);
|
||||
|
||||
var canUploadToCurrentPath = this
|
||||
.WhenAnyValue(x => x.CurrentPath)
|
||||
.Select(path => path != null)
|
||||
.CombineLatest(Refresh.IsExecuting, canInteract, (up, loading, can) => up && can && !loading);
|
||||
|
||||
UploadToCurrentPath = ReactiveCommand.CreateFromObservable(
|
||||
() => Observable
|
||||
.FromAsync(files.OpenRead)
|
||||
.Where(response => response.Name != null && response.Stream != null)
|
||||
.Select(args => _cloud.UploadFile(CurrentPath, args.Stream, args.Name))
|
||||
.SelectMany(task => task.ToObservable()),
|
||||
canUploadToCurrentPath);
|
||||
|
||||
UploadToCurrentPath.InvokeCommand(Refresh);
|
||||
|
||||
var canDownloadSelectedFile = this
|
||||
.WhenAnyValue(x => x.SelectedFile)
|
||||
.Select(file => file != null && !file.IsFolder)
|
||||
.CombineLatest(Refresh.IsExecuting, canInteract, (down, loading, can) => down && !loading && can);
|
||||
|
||||
DownloadSelectedFile = ReactiveCommand.CreateFromObservable(
|
||||
() => Observable
|
||||
.FromAsync(() => files.OpenWrite(SelectedFile.Name))
|
||||
.Where(stream => stream != null)
|
||||
.Select(stream => _cloud.DownloadFile(SelectedFile.Path, stream))
|
||||
.SelectMany(task => task.ToObservable()),
|
||||
canDownloadSelectedFile);
|
||||
DownloadSelectedFile = ReactiveCommand.CreateFromObservable(
|
||||
() => Observable
|
||||
.FromAsync(() => files.OpenWrite(SelectedFile.Name))
|
||||
.Where(stream => stream != null)
|
||||
.Select(stream => _cloud.DownloadFile(SelectedFile.Path, stream))
|
||||
.SelectMany(task => task.ToObservable()),
|
||||
canDownloadSelectedFile);
|
||||
|
||||
var canLogout = cloud
|
||||
.IsAuthorized
|
||||
.DistinctUntilChanged()
|
||||
.Select(loggedIn => loggedIn && (
|
||||
cloud.SupportsDirectAuth ||
|
||||
cloud.SupportsOAuth ||
|
||||
cloud.SupportsHostAuth))
|
||||
.CombineLatest(canInteract, (logout, interact) => logout && interact)
|
||||
.ObserveOn(RxApp.MainThreadScheduler);
|
||||
var canLogout = cloud
|
||||
.IsAuthorized
|
||||
.DistinctUntilChanged()
|
||||
.Select(loggedIn => loggedIn && (
|
||||
cloud.SupportsDirectAuth ||
|
||||
cloud.SupportsOAuth ||
|
||||
cloud.SupportsHostAuth))
|
||||
.CombineLatest(canInteract, (logout, interact) => logout && interact)
|
||||
.ObserveOn(RxApp.MainThreadScheduler);
|
||||
|
||||
Logout = ReactiveCommand.CreateFromTask(cloud.Logout, canLogout);
|
||||
Logout = ReactiveCommand.CreateFromTask(cloud.Logout, canLogout);
|
||||
|
||||
_canLogout = canLogout
|
||||
.ToProperty(this, x => x.CanLogout);
|
||||
_canLogout = canLogout
|
||||
.ToProperty(this, x => x.CanLogout);
|
||||
|
||||
var canDeleteSelection = this
|
||||
.WhenAnyValue(x => x.SelectedFile)
|
||||
.Select(file => file != null && !file.IsFolder)
|
||||
.CombineLatest(Refresh.IsExecuting, canInteract, (del, loading, ci) => del && !loading && ci);
|
||||
var canDeleteSelection = this
|
||||
.WhenAnyValue(x => x.SelectedFile)
|
||||
.Select(file => file != null && !file.IsFolder)
|
||||
.CombineLatest(Refresh.IsExecuting, canInteract, (del, loading, ci) => del && !loading && ci);
|
||||
|
||||
DeleteSelectedFile = ReactiveCommand.CreateFromTask(
|
||||
() => cloud.Delete(SelectedFile.Path, SelectedFile.IsFolder),
|
||||
canDeleteSelection);
|
||||
DeleteSelectedFile = ReactiveCommand.CreateFromTask(
|
||||
() => cloud.Delete(SelectedFile.Path, SelectedFile.IsFolder),
|
||||
canDeleteSelection);
|
||||
|
||||
DeleteSelectedFile.InvokeCommand(Refresh);
|
||||
DeleteSelectedFile.InvokeCommand(Refresh);
|
||||
|
||||
var canUnselectFile = this
|
||||
.WhenAnyValue(x => x.SelectedFile)
|
||||
.Select(selection => selection != null)
|
||||
.CombineLatest(Refresh.IsExecuting, canInteract, (sel, loading, ci) => sel && !loading && ci);
|
||||
var canUnselectFile = this
|
||||
.WhenAnyValue(x => x.SelectedFile)
|
||||
.Select(selection => selection != null)
|
||||
.CombineLatest(Refresh.IsExecuting, canInteract, (sel, loading, ci) => sel && !loading && ci);
|
||||
|
||||
UnselectFile = ReactiveCommand.Create(
|
||||
() => { SelectedFile = null; },
|
||||
canUnselectFile);
|
||||
UnselectFile = ReactiveCommand.Create(
|
||||
() => { SelectedFile = null; },
|
||||
canUnselectFile);
|
||||
|
||||
UploadToCurrentPath.ThrownExceptions
|
||||
.Merge(DeleteSelectedFile.ThrownExceptions)
|
||||
.Merge(DownloadSelectedFile.ThrownExceptions)
|
||||
.Merge(Refresh.ThrownExceptions)
|
||||
.Merge(getBreadCrumbs.ThrownExceptions)
|
||||
.Log(this, $"Exception occured in provider {cloud.Name}")
|
||||
.Subscribe();
|
||||
UploadToCurrentPath.ThrownExceptions
|
||||
.Merge(DeleteSelectedFile.ThrownExceptions)
|
||||
.Merge(DownloadSelectedFile.ThrownExceptions)
|
||||
.Merge(Refresh.ThrownExceptions)
|
||||
.Merge(getBreadCrumbs.ThrownExceptions)
|
||||
.Log(this, $"Exception occured in provider {cloud.Name}")
|
||||
.Subscribe();
|
||||
|
||||
this.WhenAnyValue(x => x.CurrentPath)
|
||||
.Subscribe(path => state.CurrentPath = path);
|
||||
this.WhenAnyValue(x => x.CurrentPath)
|
||||
.Subscribe(path => state.CurrentPath = path);
|
||||
|
||||
this.WhenAnyValue(x => x.Auth.IsAuthenticated)
|
||||
.Select(authenticated => authenticated ? _cloud.Parameters?.Token : null)
|
||||
.Subscribe(token => state.Token = token);
|
||||
this.WhenAnyValue(x => x.Auth.IsAuthenticated)
|
||||
.Select(authenticated => authenticated ? _cloud.Parameters?.Token : null)
|
||||
.Subscribe(token => state.Token = token);
|
||||
|
||||
this.WhenAnyValue(x => x.Auth.IsAuthenticated)
|
||||
.Select(authenticated => authenticated ? _cloud.Parameters?.User : null)
|
||||
.Subscribe(user => state.User = user);
|
||||
this.WhenAnyValue(x => x.Auth.IsAuthenticated)
|
||||
.Select(authenticated => authenticated ? _cloud.Parameters?.User : null)
|
||||
.Subscribe(user => state.User = user);
|
||||
|
||||
this.WhenActivated(ActivateAutoRefresh);
|
||||
}
|
||||
this.WhenActivated(ActivateAutoRefresh);
|
||||
}
|
||||
|
||||
[Reactive]
|
||||
public int RefreshingIn { get; private set; }
|
||||
[Reactive]
|
||||
public int RefreshingIn { get; private set; }
|
||||
|
||||
[Reactive]
|
||||
public IFileViewModel SelectedFile { get; set; }
|
||||
[Reactive]
|
||||
public IFileViewModel SelectedFile { get; set; }
|
||||
|
||||
public bool IsCurrentPathEmpty => _isCurrentPathEmpty.Value;
|
||||
public bool IsCurrentPathEmpty => _isCurrentPathEmpty.Value;
|
||||
|
||||
public IEnumerable<IFileViewModel> Files => _files.Value;
|
||||
public IEnumerable<IFileViewModel> Files => _files.Value;
|
||||
|
||||
public IEnumerable<IFolderViewModel> BreadCrumbs => _breadCrumbs.Value;
|
||||
public IEnumerable<IFolderViewModel> BreadCrumbs => _breadCrumbs.Value;
|
||||
|
||||
public bool ShowBreadCrumbs => _showBreadCrumbs.Value;
|
||||
public bool ShowBreadCrumbs => _showBreadCrumbs.Value;
|
||||
|
||||
public bool HideBreadCrumbs => _hideBreadCrumbs.Value;
|
||||
public bool HideBreadCrumbs => _hideBreadCrumbs.Value;
|
||||
|
||||
public string CurrentPath => _currentPath?.Value;
|
||||
public string CurrentPath => _currentPath?.Value;
|
||||
|
||||
public bool CanLogout => _canLogout.Value;
|
||||
public bool CanLogout => _canLogout.Value;
|
||||
|
||||
public bool IsLoading => _isLoading.Value;
|
||||
public bool IsLoading => _isLoading.Value;
|
||||
|
||||
public bool HasErrorMessage => _hasErrorMessage.Value;
|
||||
public bool HasErrorMessage => _hasErrorMessage.Value;
|
||||
|
||||
public bool IsReady => _isReady.Value;
|
||||
public bool IsReady => _isReady.Value;
|
||||
|
||||
public bool CanInteract => _canInteract?.Value ?? false;
|
||||
public bool CanInteract => _canInteract?.Value ?? false;
|
||||
|
||||
public IAuthViewModel Auth { get; }
|
||||
public IAuthViewModel Auth { get; }
|
||||
|
||||
public IRenameFileViewModel Rename { get; }
|
||||
public IRenameFileViewModel Rename { get; }
|
||||
|
||||
public ICreateFolderViewModel Folder { get; }
|
||||
public ICreateFolderViewModel Folder { get; }
|
||||
|
||||
public ViewModelActivator Activator { get; } = new ViewModelActivator();
|
||||
public ViewModelActivator Activator { get; } = new();
|
||||
|
||||
public Guid Id => _cloud.Id;
|
||||
public Guid Id => _cloud.Id;
|
||||
|
||||
public string Name => _cloud.Name;
|
||||
public string Name => _cloud.Name;
|
||||
|
||||
public DateTime Created => _cloud.Created;
|
||||
public DateTime Created => _cloud.Created;
|
||||
|
||||
public string Size => _cloud.Size?.ByteSizeToString() ?? "Unknown";
|
||||
public string Size => _cloud.Size?.ByteSizeToString() ?? "Unknown";
|
||||
|
||||
public string Description => $"{_cloud.Name} file system.";
|
||||
public string Description => $"{_cloud.Name} file system.";
|
||||
|
||||
public ReactiveCommand<Unit, Unit> DownloadSelectedFile { get; }
|
||||
public ReactiveCommand<Unit, Unit> DownloadSelectedFile { get; }
|
||||
|
||||
public ReactiveCommand<Unit, Unit> UploadToCurrentPath { get; }
|
||||
public ReactiveCommand<Unit, Unit> UploadToCurrentPath { get; }
|
||||
|
||||
public ReactiveCommand<Unit, Unit> DeleteSelectedFile { get; }
|
||||
public ReactiveCommand<Unit, Unit> DeleteSelectedFile { get; }
|
||||
|
||||
public ReactiveCommand<Unit, Unit> UnselectFile { get; }
|
||||
public ReactiveCommand<Unit, Unit> UnselectFile { get; }
|
||||
|
||||
public ReactiveCommand<Unit, IEnumerable<FileModel>> Refresh { get; }
|
||||
public ReactiveCommand<Unit, IEnumerable<FileModel>> Refresh { get; }
|
||||
|
||||
public ReactiveCommand<Unit, Unit> Logout { get; }
|
||||
public ReactiveCommand<Unit, Unit> Logout { get; }
|
||||
|
||||
public ReactiveCommand<Unit, string> Back { get; }
|
||||
public ReactiveCommand<Unit, string> Back { get; }
|
||||
|
||||
public ReactiveCommand<Unit, string> Open { get; }
|
||||
public ReactiveCommand<Unit, string> Open { get; }
|
||||
|
||||
public ReactiveCommand<string, string> SetPath { get; }
|
||||
public ReactiveCommand<string, string> SetPath { get; }
|
||||
|
||||
private void ActivateAutoRefresh(CompositeDisposable disposable)
|
||||
{
|
||||
this.WhenAnyValue(x => x.Auth.IsAuthenticated)
|
||||
.Where(authenticated => authenticated)
|
||||
.Select(_ => Unit.Default)
|
||||
.InvokeCommand(Refresh)
|
||||
.DisposeWith(disposable);
|
||||
private void ActivateAutoRefresh(CompositeDisposable disposable)
|
||||
{
|
||||
this.WhenAnyValue(x => x.Auth.IsAuthenticated)
|
||||
.Where(authenticated => authenticated)
|
||||
.Select(_ => Unit.Default)
|
||||
.InvokeCommand(Refresh)
|
||||
.DisposeWith(disposable);
|
||||
|
||||
Observable.Timer(TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1))
|
||||
.Select(_ => RefreshingIn - 1)
|
||||
.Where(value => value >= 0)
|
||||
.ObserveOn(RxApp.MainThreadScheduler)
|
||||
.Subscribe(x => RefreshingIn = x)
|
||||
.DisposeWith(disposable);
|
||||
Observable.Timer(TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1))
|
||||
.Select(_ => RefreshingIn - 1)
|
||||
.Where(value => value >= 0)
|
||||
.ObserveOn(RxApp.MainThreadScheduler)
|
||||
.Subscribe(x => RefreshingIn = x)
|
||||
.DisposeWith(disposable);
|
||||
|
||||
this.WhenAnyValue(x => x.RefreshingIn)
|
||||
.Skip(1)
|
||||
.Where(refreshing => refreshing == 0)
|
||||
.Log(this, $"Refreshing provider {_cloud.Name} path {CurrentPath}")
|
||||
.Select(_ => Unit.Default)
|
||||
.InvokeCommand(Refresh)
|
||||
.DisposeWith(disposable);
|
||||
this.WhenAnyValue(x => x.RefreshingIn)
|
||||
.Skip(1)
|
||||
.Where(refreshing => refreshing == 0)
|
||||
.Log(this, $"Refreshing provider {_cloud.Name} path {CurrentPath}")
|
||||
.Select(_ => Unit.Default)
|
||||
.InvokeCommand(Refresh)
|
||||
.DisposeWith(disposable);
|
||||
|
||||
Refresh.Select(_ => 30)
|
||||
.StartWith(30)
|
||||
.ObserveOn(RxApp.MainThreadScheduler)
|
||||
.Subscribe(x => RefreshingIn = x)
|
||||
.DisposeWith(disposable);
|
||||
Refresh.Select(_ => 30)
|
||||
.StartWith(30)
|
||||
.ObserveOn(RxApp.MainThreadScheduler)
|
||||
.Subscribe(x => RefreshingIn = x)
|
||||
.DisposeWith(disposable);
|
||||
|
||||
this.WhenAnyValue(x => x.CanInteract)
|
||||
.Skip(1)
|
||||
.Where(interact => interact)
|
||||
.Select(x => Unit.Default)
|
||||
.InvokeCommand(Refresh)
|
||||
.DisposeWith(disposable);
|
||||
}
|
||||
this.WhenAnyValue(x => x.CanInteract)
|
||||
.Skip(1)
|
||||
.Where(interact => interact)
|
||||
.Select(x => Unit.Default)
|
||||
.InvokeCommand(Refresh)
|
||||
.DisposeWith(disposable);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,107 +9,106 @@ using ReactiveUI.Fody.Helpers;
|
|||
using ReactiveUI.Validation.Extensions;
|
||||
using ReactiveUI.Validation.Helpers;
|
||||
|
||||
namespace Camelotia.Presentation.ViewModels
|
||||
namespace Camelotia.Presentation.ViewModels;
|
||||
|
||||
public delegate ICreateFolderViewModel CreateFolderViewModelFactory(ICloudViewModel providerViewModel);
|
||||
|
||||
public sealed class CreateFolderViewModel : ReactiveValidationObject, ICreateFolderViewModel
|
||||
{
|
||||
public delegate ICreateFolderViewModel CreateFolderViewModelFactory(ICloudViewModel providerViewModel);
|
||||
private readonly ObservableAsPropertyHelper<string> _errorMessage;
|
||||
private readonly ObservableAsPropertyHelper<bool> _hasErrorMessage;
|
||||
private readonly ObservableAsPropertyHelper<bool> _isLoading;
|
||||
private readonly ObservableAsPropertyHelper<string> _path;
|
||||
|
||||
public sealed class CreateFolderViewModel : ReactiveValidationObject, ICreateFolderViewModel
|
||||
public CreateFolderViewModel(CreateFolderState state, ICloudViewModel owner, ICloud provider)
|
||||
{
|
||||
private readonly ObservableAsPropertyHelper<string> _errorMessage;
|
||||
private readonly ObservableAsPropertyHelper<bool> _hasErrorMessage;
|
||||
private readonly ObservableAsPropertyHelper<bool> _isLoading;
|
||||
private readonly ObservableAsPropertyHelper<string> _path;
|
||||
_path = owner
|
||||
.WhenAnyValue(x => x.CurrentPath)
|
||||
.ToProperty(this, x => x.Path);
|
||||
|
||||
public CreateFolderViewModel(CreateFolderState state, ICloudViewModel owner, ICloud provider)
|
||||
{
|
||||
_path = owner
|
||||
.WhenAnyValue(x => x.CurrentPath)
|
||||
.ToProperty(this, x => x.Path);
|
||||
this.ValidationRule(
|
||||
x => x.Name,
|
||||
name => !string.IsNullOrWhiteSpace(name),
|
||||
"Folder name shouldn't be empty.");
|
||||
|
||||
this.ValidationRule(
|
||||
x => x.Name,
|
||||
name => !string.IsNullOrWhiteSpace(name),
|
||||
"Folder name shouldn't be empty.");
|
||||
var pathRule = this.ValidationRule(
|
||||
x => x.Path,
|
||||
path => !string.IsNullOrWhiteSpace(path),
|
||||
"Path shouldn't be empty");
|
||||
|
||||
var pathRule = this.ValidationRule(
|
||||
x => x.Path,
|
||||
path => !string.IsNullOrWhiteSpace(path),
|
||||
"Path shouldn't be empty");
|
||||
Create = ReactiveCommand.CreateFromTask(
|
||||
() => provider.CreateFolder(Path, Name),
|
||||
this.IsValid());
|
||||
|
||||
Create = ReactiveCommand.CreateFromTask(
|
||||
() => provider.CreateFolder(Path, Name),
|
||||
this.IsValid());
|
||||
_isLoading = Create.IsExecuting
|
||||
.ToProperty(this, x => x.IsLoading);
|
||||
|
||||
_isLoading = Create.IsExecuting
|
||||
.ToProperty(this, x => x.IsLoading);
|
||||
var canInteract = owner
|
||||
.WhenAnyValue(x => x.CanInteract)
|
||||
.Skip(1)
|
||||
.StartWith(true);
|
||||
|
||||
var canInteract = owner
|
||||
.WhenAnyValue(x => x.CanInteract)
|
||||
.Skip(1)
|
||||
.StartWith(true);
|
||||
var canOpen = this
|
||||
.WhenAnyValue(x => x.IsVisible)
|
||||
.Select(visible => !visible)
|
||||
.CombineLatest(
|
||||
canInteract,
|
||||
pathRule.WhenAnyValue(x => x.IsValid),
|
||||
(visible, interact, path) => visible && provider.CanCreateFolder && interact && path);
|
||||
|
||||
var canOpen = this
|
||||
.WhenAnyValue(x => x.IsVisible)
|
||||
.Select(visible => !visible)
|
||||
.CombineLatest(
|
||||
canInteract,
|
||||
pathRule.WhenAnyValue(x => x.IsValid),
|
||||
(visible, interact, path) => visible && provider.CanCreateFolder && interact && path);
|
||||
var canClose = this
|
||||
.WhenAnyValue(x => x.IsVisible)
|
||||
.Select(visible => visible);
|
||||
|
||||
var canClose = this
|
||||
.WhenAnyValue(x => x.IsVisible)
|
||||
.Select(visible => visible);
|
||||
Open = ReactiveCommand.Create(() => { }, canOpen);
|
||||
Close = ReactiveCommand.Create(() => { }, canClose);
|
||||
|
||||
Open = ReactiveCommand.Create(() => { }, canOpen);
|
||||
Close = ReactiveCommand.Create(() => { }, canClose);
|
||||
Open.Select(unit => true)
|
||||
.Merge(Close.Select(unit => false))
|
||||
.Subscribe(visible => IsVisible = visible);
|
||||
|
||||
Open.Select(unit => true)
|
||||
.Merge(Close.Select(unit => false))
|
||||
.Subscribe(visible => IsVisible = visible);
|
||||
Close.Subscribe(x => Name = string.Empty);
|
||||
Create.InvokeCommand(Close);
|
||||
|
||||
Close.Subscribe(x => Name = string.Empty);
|
||||
Create.InvokeCommand(Close);
|
||||
_hasErrorMessage = Create
|
||||
.ThrownExceptions
|
||||
.Select(exception => true)
|
||||
.Merge(Close.Select(unit => false))
|
||||
.ToProperty(this, x => x.HasErrorMessage);
|
||||
|
||||
_hasErrorMessage = Create
|
||||
.ThrownExceptions
|
||||
.Select(exception => true)
|
||||
.Merge(Close.Select(unit => false))
|
||||
.ToProperty(this, x => x.HasErrorMessage);
|
||||
_errorMessage = Create
|
||||
.ThrownExceptions
|
||||
.Select(exception => exception.Message)
|
||||
.Log(this, $"Create folder error occured in {provider.Name}")
|
||||
.Merge(Close.Select(unit => string.Empty))
|
||||
.ToProperty(this, x => x.ErrorMessage);
|
||||
|
||||
_errorMessage = Create
|
||||
.ThrownExceptions
|
||||
.Select(exception => exception.Message)
|
||||
.Log(this, $"Create folder error occured in {provider.Name}")
|
||||
.Merge(Close.Select(unit => string.Empty))
|
||||
.ToProperty(this, x => x.ErrorMessage);
|
||||
Name = state.Name;
|
||||
IsVisible = state.IsVisible;
|
||||
|
||||
Name = state.Name;
|
||||
IsVisible = state.IsVisible;
|
||||
|
||||
this.WhenAnyValue(x => x.Name)
|
||||
.Subscribe(name => state.Name = name);
|
||||
this.WhenAnyValue(x => x.IsVisible)
|
||||
.Subscribe(visible => state.IsVisible = visible);
|
||||
}
|
||||
|
||||
[Reactive]
|
||||
public string Name { get; set; }
|
||||
|
||||
[Reactive]
|
||||
public bool IsVisible { get; set; }
|
||||
|
||||
public string ErrorMessage => _errorMessage.Value;
|
||||
|
||||
public bool HasErrorMessage => _hasErrorMessage.Value;
|
||||
|
||||
public bool IsLoading => _isLoading.Value;
|
||||
|
||||
public string Path => _path.Value;
|
||||
|
||||
public ReactiveCommand<Unit, Unit> Create { get; }
|
||||
|
||||
public ReactiveCommand<Unit, Unit> Close { get; }
|
||||
|
||||
public ReactiveCommand<Unit, Unit> Open { get; }
|
||||
this.WhenAnyValue(x => x.Name)
|
||||
.Subscribe(name => state.Name = name);
|
||||
this.WhenAnyValue(x => x.IsVisible)
|
||||
.Subscribe(visible => state.IsVisible = visible);
|
||||
}
|
||||
|
||||
[Reactive]
|
||||
public string Name { get; set; }
|
||||
|
||||
[Reactive]
|
||||
public bool IsVisible { get; set; }
|
||||
|
||||
public string ErrorMessage => _errorMessage.Value;
|
||||
|
||||
public bool HasErrorMessage => _hasErrorMessage.Value;
|
||||
|
||||
public bool IsLoading => _isLoading.Value;
|
||||
|
||||
public string Path => _path.Value;
|
||||
|
||||
public ReactiveCommand<Unit, Unit> Create { get; }
|
||||
|
||||
public ReactiveCommand<Unit, Unit> Close { get; }
|
||||
|
||||
public ReactiveCommand<Unit, Unit> Open { get; }
|
||||
}
|
|
@ -9,67 +9,66 @@ using ReactiveUI.Fody.Helpers;
|
|||
using ReactiveUI.Validation.Extensions;
|
||||
using ReactiveUI.Validation.Helpers;
|
||||
|
||||
namespace Camelotia.Presentation.ViewModels
|
||||
namespace Camelotia.Presentation.ViewModels;
|
||||
|
||||
public sealed class DirectAuthViewModel : ReactiveValidationObject, IDirectAuthViewModel
|
||||
{
|
||||
public sealed class DirectAuthViewModel : ReactiveValidationObject, IDirectAuthViewModel
|
||||
private readonly ObservableAsPropertyHelper<string> _errorMessage;
|
||||
private readonly ObservableAsPropertyHelper<bool> _hasErrorMessage;
|
||||
private readonly ObservableAsPropertyHelper<bool> _isBusy;
|
||||
|
||||
public DirectAuthViewModel(DirectAuthState state, ICloud provider)
|
||||
{
|
||||
private readonly ObservableAsPropertyHelper<string> _errorMessage;
|
||||
private readonly ObservableAsPropertyHelper<bool> _hasErrorMessage;
|
||||
private readonly ObservableAsPropertyHelper<bool> _isBusy;
|
||||
this.ValidationRule(
|
||||
x => x.Username,
|
||||
name => !string.IsNullOrWhiteSpace(name),
|
||||
"User name shouldn't be null or white space.");
|
||||
|
||||
public DirectAuthViewModel(DirectAuthState state, ICloud provider)
|
||||
{
|
||||
this.ValidationRule(
|
||||
x => x.Username,
|
||||
name => !string.IsNullOrWhiteSpace(name),
|
||||
"User name shouldn't be null or white space.");
|
||||
this.ValidationRule(
|
||||
x => x.Password,
|
||||
pass => !string.IsNullOrWhiteSpace(pass),
|
||||
"Password shouldn't be null or white space.");
|
||||
|
||||
this.ValidationRule(
|
||||
x => x.Password,
|
||||
pass => !string.IsNullOrWhiteSpace(pass),
|
||||
"Password shouldn't be null or white space.");
|
||||
Login = ReactiveCommand.CreateFromTask(
|
||||
() => provider.DirectAuth(Username, Password),
|
||||
this.IsValid());
|
||||
|
||||
Login = ReactiveCommand.CreateFromTask(
|
||||
() => provider.DirectAuth(Username, Password),
|
||||
this.IsValid());
|
||||
_isBusy = Login
|
||||
.IsExecuting
|
||||
.ToProperty(this, x => x.IsBusy);
|
||||
|
||||
_isBusy = Login
|
||||
.IsExecuting
|
||||
.ToProperty(this, x => x.IsBusy);
|
||||
_errorMessage = Login
|
||||
.ThrownExceptions
|
||||
.Select(exception => exception.Message)
|
||||
.Log(this, $"Direct auth error occured in {provider.Name}")
|
||||
.ToProperty(this, x => x.ErrorMessage);
|
||||
|
||||
_errorMessage = Login
|
||||
.ThrownExceptions
|
||||
.Select(exception => exception.Message)
|
||||
.Log(this, $"Direct auth error occured in {provider.Name}")
|
||||
.ToProperty(this, x => x.ErrorMessage);
|
||||
_hasErrorMessage = Login
|
||||
.ThrownExceptions
|
||||
.Select(exception => true)
|
||||
.Merge(Login.Select(unit => false))
|
||||
.ToProperty(this, x => x.HasErrorMessage);
|
||||
|
||||
_hasErrorMessage = Login
|
||||
.ThrownExceptions
|
||||
.Select(exception => true)
|
||||
.Merge(Login.Select(unit => false))
|
||||
.ToProperty(this, x => x.HasErrorMessage);
|
||||
Username = state.Username;
|
||||
Password = state.Password;
|
||||
|
||||
Username = state.Username;
|
||||
Password = state.Password;
|
||||
|
||||
this.WhenAnyValue(x => x.Username)
|
||||
.Subscribe(name => state.Username = name);
|
||||
this.WhenAnyValue(x => x.Password)
|
||||
.Subscribe(pass => state.Password = pass);
|
||||
}
|
||||
|
||||
[Reactive]
|
||||
public string Username { get; set; }
|
||||
|
||||
[Reactive]
|
||||
public string Password { get; set; }
|
||||
|
||||
public bool IsBusy => _isBusy.Value;
|
||||
|
||||
public string ErrorMessage => _errorMessage.Value;
|
||||
|
||||
public bool HasErrorMessage => _hasErrorMessage.Value;
|
||||
|
||||
public ReactiveCommand<Unit, Unit> Login { get; }
|
||||
this.WhenAnyValue(x => x.Username)
|
||||
.Subscribe(name => state.Username = name);
|
||||
this.WhenAnyValue(x => x.Password)
|
||||
.Subscribe(pass => state.Password = pass);
|
||||
}
|
||||
|
||||
[Reactive]
|
||||
public string Username { get; set; }
|
||||
|
||||
[Reactive]
|
||||
public string Password { get; set; }
|
||||
|
||||
public bool IsBusy => _isBusy.Value;
|
||||
|
||||
public string ErrorMessage => _errorMessage.Value;
|
||||
|
||||
public bool HasErrorMessage => _hasErrorMessage.Value;
|
||||
|
||||
public ReactiveCommand<Unit, Unit> Login { get; }
|
||||
}
|
|
@ -4,55 +4,54 @@ using Camelotia.Presentation.Interfaces;
|
|||
using Camelotia.Services.Models;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace Camelotia.Presentation.ViewModels
|
||||
namespace Camelotia.Presentation.ViewModels;
|
||||
|
||||
public delegate IFileViewModel FileViewModelFactory(FileModel file, ICloudViewModel provider);
|
||||
|
||||
public sealed class FileViewModel : ReactiveObject, IFileViewModel
|
||||
{
|
||||
public delegate IFileViewModel FileViewModelFactory(FileModel file, ICloudViewModel provider);
|
||||
private readonly FileModel _file;
|
||||
|
||||
public sealed class FileViewModel : ReactiveObject, IFileViewModel
|
||||
public FileViewModel(ICloudViewModel provider, FileModel file)
|
||||
{
|
||||
private readonly FileModel _file;
|
||||
Provider = provider;
|
||||
_file = file;
|
||||
}
|
||||
|
||||
public FileViewModel(ICloudViewModel provider, FileModel file)
|
||||
public ICloudViewModel Provider { get; }
|
||||
|
||||
public string Modified => _file.Modified?.ToString(CultureInfo.InvariantCulture) ?? "A long time ago";
|
||||
|
||||
public string Size => _file.Size == 0 ? "Unknown" : _file.Size.ByteSizeToString();
|
||||
|
||||
public bool IsFolder => _file.IsFolder;
|
||||
|
||||
public bool IsFile => !_file.IsFolder;
|
||||
|
||||
public string Name => _file.Name;
|
||||
|
||||
public string Path => _file.Path;
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj is FileViewModel other)
|
||||
{
|
||||
Provider = provider;
|
||||
_file = file;
|
||||
return Equals(_file.Path, other._file.Path) &&
|
||||
Equals(_file.Modified, other._file.Modified) &&
|
||||
Equals(Provider, other.Provider);
|
||||
}
|
||||
|
||||
public ICloudViewModel Provider { get; }
|
||||
return false;
|
||||
}
|
||||
|
||||
public string Modified => _file.Modified?.ToString(CultureInfo.InvariantCulture) ?? "A long time ago";
|
||||
|
||||
public string Size => _file.Size == 0 ? "Unknown" : _file.Size.ByteSizeToString();
|
||||
|
||||
public bool IsFolder => _file.IsFolder;
|
||||
|
||||
public bool IsFile => !_file.IsFolder;
|
||||
|
||||
public string Name => _file.Name;
|
||||
|
||||
public string Path => _file.Path;
|
||||
|
||||
public override bool Equals(object obj)
|
||||
public override int GetHashCode()
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
if (obj is FileViewModel other)
|
||||
{
|
||||
return Equals(_file.Path, other._file.Path) &&
|
||||
Equals(_file.Modified, other._file.Modified) &&
|
||||
Equals(Provider, other.Provider);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
var hashCode = _file.Path.GetHashCode();
|
||||
hashCode = (hashCode * 397) ^ _file.Modified.GetHashCode();
|
||||
hashCode = (hashCode * 397) ^ Provider.GetHashCode();
|
||||
return hashCode;
|
||||
}
|
||||
var hashCode = _file.Path.GetHashCode();
|
||||
hashCode = (hashCode * 397) ^ _file.Modified.GetHashCode();
|
||||
hashCode = (hashCode * 397) ^ Provider.GetHashCode();
|
||||
return hashCode;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,48 +4,47 @@ using Camelotia.Presentation.Interfaces;
|
|||
using Camelotia.Services.Models;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace Camelotia.Presentation.ViewModels
|
||||
namespace Camelotia.Presentation.ViewModels;
|
||||
|
||||
public delegate IFolderViewModel FolderViewModelFactory(FolderModel folder, ICloudViewModel provider);
|
||||
|
||||
public sealed class FolderViewModel : ReactiveObject, IFolderViewModel
|
||||
{
|
||||
public delegate IFolderViewModel FolderViewModelFactory(FolderModel folder, ICloudViewModel provider);
|
||||
private readonly FolderModel _folder;
|
||||
|
||||
public sealed class FolderViewModel : ReactiveObject, IFolderViewModel
|
||||
public FolderViewModel(ICloudViewModel provider, FolderModel folder)
|
||||
{
|
||||
private readonly FolderModel _folder;
|
||||
Provider = provider;
|
||||
_folder = folder;
|
||||
Children = folder.Children?.Any() == true
|
||||
? folder.Children.Select(f => new FolderViewModel(provider, f))
|
||||
: Enumerable.Empty<IFolderViewModel>();
|
||||
}
|
||||
|
||||
public FolderViewModel(ICloudViewModel provider, FolderModel folder)
|
||||
public ICloudViewModel Provider { get; }
|
||||
|
||||
public string Name => _folder.Name;
|
||||
|
||||
public string FullPath => _folder.FullPath;
|
||||
|
||||
public IEnumerable<IFolderViewModel> Children { get; }
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is FolderViewModel other &&
|
||||
Equals(_folder.Name, other._folder.Name) &&
|
||||
Equals(_folder.FullPath, other._folder.FullPath) &&
|
||||
Equals(Provider, other.Provider);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
Provider = provider;
|
||||
_folder = folder;
|
||||
Children = folder.Children?.Any() == true
|
||||
? folder.Children.Select(f => new FolderViewModel(provider, f))
|
||||
: Enumerable.Empty<IFolderViewModel>();
|
||||
}
|
||||
|
||||
public ICloudViewModel Provider { get; }
|
||||
|
||||
public string Name => _folder.Name;
|
||||
|
||||
public string FullPath => _folder.FullPath;
|
||||
|
||||
public IEnumerable<IFolderViewModel> Children { get; }
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is FolderViewModel other &&
|
||||
Equals(_folder.Name, other._folder.Name) &&
|
||||
Equals(_folder.FullPath, other._folder.FullPath) &&
|
||||
Equals(Provider, other.Provider);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
var hashCode = _folder.Name.GetHashCode();
|
||||
hashCode = (hashCode * 397) ^ _folder.FullPath.GetHashCode();
|
||||
hashCode = (hashCode * 397) ^ Provider.GetHashCode();
|
||||
return hashCode;
|
||||
}
|
||||
var hashCode = _folder.Name.GetHashCode();
|
||||
hashCode = (hashCode * 397) ^ _folder.FullPath.GetHashCode();
|
||||
hashCode = (hashCode * 397) ^ Provider.GetHashCode();
|
||||
return hashCode;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче