Port Camelotia to Android (Xamarin.Forms) (#9)
* Update packages, add XF + Android projects * Reference proper packages, implement main view * Implement MasterDetail pattern * Implement Provider view * Add authentication pages * Fix login-logout issues * Pull2refresh, use spaces instead of tabs * Hide unrelated auth pages * Improved GUI and styles * Update README.md * Fix extensions * Wider images * Align images properly * Images were too big * Better vendor descriptions * Build only Avalonia project now * Cleanup * GUI tweaks * Implement file picker * Implement file upload & download * Fix first provider won't get selected * Implement authentication service
|
@ -5,16 +5,19 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="coverlet.msbuild" Version="2.3.2">
|
||||
<PackageReference Include="coverlet.msbuild" Version="2.5.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="FluentAssertions" Version="5.5.3" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.8.0" />
|
||||
<PackageReference Include="ReactiveUI.Testing" Version="9.1.1" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
|
||||
<PackageReference Include="ReactiveUI.Testing" Version="9.5.1" />
|
||||
<PackageReference Include="NSubstitute" Version="3.1.0" />
|
||||
<PackageReference Include="xunit" Version="2.3.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
|
||||
<PackageReference Include="xunit" Version="2.4.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -0,0 +1,132 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{24CE3C36-16B9-426D-AA0C-5961ECF8D88C}</ProjectGuid>
|
||||
<ProjectTypeGuids>{EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||
<TemplateGuid>{9AA2D3C6-3393-45F1-8E7C-5A9901728795}</TemplateGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<RootNamespace>Camelotia.Presentation.Xamarin.Droid</RootNamespace>
|
||||
<AssemblyName>Camelotia.Presentation.Xamarin.Android</AssemblyName>
|
||||
<AndroidApplication>True</AndroidApplication>
|
||||
<AndroidResgenFile>Resources\Resource.designer.cs</AndroidResgenFile>
|
||||
<AndroidResgenClass>Resource</AndroidResgenClass>
|
||||
<AndroidManifest>Properties\AndroidManifest.xml</AndroidManifest>
|
||||
<MonoAndroidResourcePrefix>Resources</MonoAndroidResourcePrefix>
|
||||
<MonoAndroidAssetsPrefix>Assets</MonoAndroidAssetsPrefix>
|
||||
<AndroidUseLatestPlatformSdk>false</AndroidUseLatestPlatformSdk>
|
||||
<TargetFrameworkVersion>v8.1</TargetFrameworkVersion>
|
||||
<AndroidHttpClientHandlerType>Xamarin.Android.Net.AndroidClientHandler</AndroidHttpClientHandlerType>
|
||||
<NuGetPackageImportStamp>
|
||||
</NuGetPackageImportStamp>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>portable</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug</OutputPath>
|
||||
<DefineConstants>DEBUG;</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<AndroidLinkMode>None</AndroidLinkMode>
|
||||
<AotAssemblies>false</AotAssemblies>
|
||||
<EnableLLVM>false</EnableLLVM>
|
||||
<BundleAssemblies>false</BundleAssemblies>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release</OutputPath>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<AndroidManagedSymbols>true</AndroidManagedSymbols>
|
||||
<AndroidUseSharedRuntime>false</AndroidUseSharedRuntime>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Mono.Android" />
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.Reactive" Version="4.1.2" />
|
||||
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="4.5.2" />
|
||||
<PackageReference Include="ReactiveUI.AndroidSupport">
|
||||
<Version>9.5.1</Version>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Xamarin.Forms" Version="3.4.0.1008975" />
|
||||
<PackageReference Include="Xamarin.Android.Support.Design" Version="28.0.0" />
|
||||
<PackageReference Include="Xamarin.Android.Support.v7.AppCompat" Version="28.0.0" />
|
||||
<PackageReference Include="Xamarin.Android.Support.v4" Version="28.0.0" />
|
||||
<PackageReference Include="Xamarin.Android.Support.v7.CardView" Version="28.0.0" />
|
||||
<PackageReference Include="Xamarin.Android.Support.v7.MediaRouter" Version="28.0.0" />
|
||||
<PackageReference Include="Xamarin.Plugin.FilePicker">
|
||||
<Version>2.0.135</Version>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System.Threading.Tasks.Extensions">
|
||||
<HintPath>$(UserProfile)\.nuget\packages\system.threading.tasks.extensions\4.5.1\lib\netstandard2.0\System.Threading.Tasks.Extensions.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="MainActivity.cs" />
|
||||
<Compile Include="Resources\Resource.designer.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Services\AndroidAuthenticator.cs" />
|
||||
<Compile Include="Services\AndroidFileManager.cs" />
|
||||
<Compile Include="WebActivity.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="Assets\AboutAssets.txt" />
|
||||
<None Include="Properties\AndroidManifest.xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\layout\Tabbar.axml" />
|
||||
<AndroidResource Include="Resources\layout\Toolbar.axml" />
|
||||
<AndroidResource Include="Resources\values\styles.xml" />
|
||||
<AndroidResource Include="Resources\values\colors.xml" />
|
||||
<AndroidResource Include="Resources\mipmap-anydpi-v26\icon.xml" />
|
||||
<AndroidResource Include="Resources\mipmap-anydpi-v26\icon_round.xml" />
|
||||
<AndroidResource Include="Resources\mipmap-hdpi\icon.png" />
|
||||
<AndroidResource Include="Resources\mipmap-hdpi\launcher_foreground.png" />
|
||||
<AndroidResource Include="Resources\mipmap-mdpi\icon.png" />
|
||||
<AndroidResource Include="Resources\mipmap-mdpi\launcher_foreground.png" />
|
||||
<AndroidResource Include="Resources\mipmap-xhdpi\icon.png" />
|
||||
<AndroidResource Include="Resources\mipmap-xhdpi\launcher_foreground.png" />
|
||||
<AndroidResource Include="Resources\mipmap-xxhdpi\icon.png" />
|
||||
<AndroidResource Include="Resources\mipmap-xxhdpi\launcher_foreground.png" />
|
||||
<AndroidResource Include="Resources\mipmap-xxxhdpi\icon.png" />
|
||||
<AndroidResource Include="Resources\mipmap-xxxhdpi\launcher_foreground.png" />
|
||||
<AndroidResource Include="Resources\drawable\xamarin_logo.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Resources\drawable-hdpi\" />
|
||||
<Folder Include="Resources\drawable-xhdpi\" />
|
||||
<Folder Include="Resources\drawable-xxhdpi\" />
|
||||
<Folder Include="Resources\drawable-xxxhdpi\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Camelotia.Presentation.Xamarin\Camelotia.Presentation.Xamarin.csproj">
|
||||
<Project>{4c429bb0-c9d8-43d0-bac3-d5dd93e89d65}</Project>
|
||||
<Name>Camelotia.Presentation.Xamarin</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Camelotia.Presentation\Camelotia.Presentation.csproj">
|
||||
<Project>{777FBFA6-ECFA-42F5-AC5F-EFC4B2D4AE6B}</Project>
|
||||
<Name>Camelotia.Presentation</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Camelotia.Services\Camelotia.Services.csproj">
|
||||
<Project>{283B8F56-AB9F-4556-AB93-AAC54171841C}</Project>
|
||||
<Name>Camelotia.Services</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AndroidResource Include="Resources\layout\WebActivity.axml">
|
||||
<SubType>Designer</SubType>
|
||||
</AndroidResource>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" />
|
||||
</Project>
|
|
@ -0,0 +1,73 @@
|
|||
using Camelotia.Presentation.Interfaces;
|
||||
using Camelotia.Presentation.ViewModels;
|
||||
using Camelotia.Presentation.Xamarin.Droid.Services;
|
||||
using Camelotia.Services.Providers;
|
||||
using Camelotia.Services.Storages;
|
||||
using System.Reactive.Concurrency;
|
||||
using System.Reactive.Subjects;
|
||||
using System;
|
||||
using Android.App;
|
||||
using Android.Content.PM;
|
||||
using Android.OS;
|
||||
using Android.Content;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace Camelotia.Presentation.Xamarin.Droid
|
||||
{
|
||||
[Activity(
|
||||
Label = "Camelotia.Presentation.Xamarin",
|
||||
Icon = "@mipmap/icon",
|
||||
Theme = "@style/MainTheme",
|
||||
MainLauncher = true,
|
||||
ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
|
||||
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
|
||||
{
|
||||
private readonly ISubject<string> _authenticationCodeReceived = new Subject<string>();
|
||||
|
||||
public IObservable<string> AuthenticationCodeReceived => _authenticationCodeReceived;
|
||||
|
||||
protected override void OnCreate(Bundle savedInstanceState)
|
||||
{
|
||||
TabLayoutResource = Resource.Layout.Tabbar;
|
||||
ToolbarResource = Resource.Layout.Toolbar;
|
||||
|
||||
base.OnCreate(savedInstanceState);
|
||||
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
|
||||
LoadApplication(new App(BuildMainViewModel()));
|
||||
}
|
||||
|
||||
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
|
||||
{
|
||||
base.OnActivityResult(requestCode, resultCode, data);
|
||||
if (requestCode != 42 || resultCode != Result.Ok) return;
|
||||
var code = data.GetStringExtra("token");
|
||||
_authenticationCodeReceived.OnNext(code);
|
||||
}
|
||||
|
||||
private IMainViewModel BuildMainViewModel()
|
||||
{
|
||||
var currentThread = CurrentThreadScheduler.Instance;
|
||||
var mainThread = RxApp.MainThreadScheduler;
|
||||
var cache = new AkavacheTokenStorage();
|
||||
|
||||
return new MainViewModel(
|
||||
(provider, files, auth) => new ProviderViewModel(auth, files, currentThread, mainThread, provider),
|
||||
provider => new AuthViewModel(
|
||||
new DirectAuthViewModel(currentThread, mainThread, provider),
|
||||
new OAuthViewModel(currentThread, mainThread, provider),
|
||||
currentThread,
|
||||
provider
|
||||
),
|
||||
new ProviderStorage(
|
||||
new VkontakteFileSystemProvider(cache),
|
||||
new YandexFileSystemProvider(
|
||||
new AndroidAuthenticator(this), cache
|
||||
)
|
||||
),
|
||||
new AndroidFileManager(this),
|
||||
currentThread,
|
||||
mainThread
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="com.companyname">
|
||||
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="27" />
|
||||
<application android:label="Camelotia.Presentation.Xamarin.Android"></application>
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
</manifest>
|
|
@ -0,0 +1,20 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using Android.App;
|
||||
|
||||
[assembly: AssemblyTitle("Camelotia.Presentation.Xamarin.Android")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("Camelotia.Presentation.Xamarin.Android")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2014")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
|
||||
[assembly: UsesPermission(Android.Manifest.Permission.Internet)]
|
||||
[assembly: UsesPermission(Android.Manifest.Permission.WriteExternalStorage)]
|
7516
Camelotia.Presentation.Xamarin.Android/Resources/Resource.designer.cs
сгенерированный
Normal file
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<android.support.design.widget.TabLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/sliding_tabs"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/colorPrimary"
|
||||
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
|
||||
app:tabIndicatorColor="@android:color/white"
|
||||
app:tabGravity="fill"
|
||||
app:tabMode="fixed" />
|
|
@ -0,0 +1,9 @@
|
|||
<android.support.v7.widget.Toolbar
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/colorPrimary"
|
||||
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
|
||||
android:popupTheme="@style/ThemeOverlay.AppCompat.Light" />
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<WebView
|
||||
android:id="@+id/web_activity_web_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
</LinearLayout>
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/launcher_background" />
|
||||
<foreground android:drawable="@mipmap/launcher_foreground" />
|
||||
</adaptive-icon>
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/launcher_background" />
|
||||
<foreground android:drawable="@mipmap/launcher_foreground" />
|
||||
</adaptive-icon>
|
После Ширина: | Высота: | Размер: 4.6 KiB |
Двоичные данные
Camelotia.Presentation.Xamarin.Android/Resources/mipmap-hdpi/launcher_foreground.png
Normal file
После Ширина: | Высота: | Размер: 11 KiB |
После Ширина: | Высота: | Размер: 2.7 KiB |
Двоичные данные
Camelotia.Presentation.Xamarin.Android/Resources/mipmap-mdpi/launcher_foreground.png
Normal file
После Ширина: | Высота: | Размер: 6.3 KiB |
После Ширина: | Высота: | Размер: 6.9 KiB |
Двоичные данные
Camelotia.Presentation.Xamarin.Android/Resources/mipmap-xhdpi/launcher_foreground.png
Normal file
После Ширина: | Высота: | Размер: 18 KiB |
После Ширина: | Высота: | Размер: 12 KiB |
Двоичные данные
Camelotia.Presentation.Xamarin.Android/Resources/mipmap-xxhdpi/launcher_foreground.png
Normal file
После Ширина: | Высота: | Размер: 33 KiB |
Двоичные данные
Camelotia.Presentation.Xamarin.Android/Resources/mipmap-xxxhdpi/icon.png
Normal file
После Ширина: | Высота: | Размер: 19 KiB |
Двоичные данные
Camelotia.Presentation.Xamarin.Android/Resources/mipmap-xxxhdpi/launcher_foreground.png
Normal file
После Ширина: | Высота: | Размер: 51 KiB |
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="launcher_background">#000063</color>
|
||||
<color name="colorPrimary">#311b92</color>
|
||||
<color name="colorPrimaryDark">#000063</color>
|
||||
<color name="colorAccent">#6746c3</color>
|
||||
<color name="ListViewSelected">#c5cae9</color>
|
||||
<color name="ListViewHighlighted">#c5cae9</color>
|
||||
</resources>
|
|
@ -0,0 +1,21 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<resources>
|
||||
<style name="MainTheme" parent="MainTheme.Base"></style>
|
||||
<style name="MainTheme.Base" parent="Theme.AppCompat.Light.DarkActionBar">
|
||||
<item name="windowNoTitle">true</item>
|
||||
<item name="windowActionBar">false</item>
|
||||
<item name="colorPrimary">#311b92</item>
|
||||
<item name="colorPrimaryDark">#000063</item>
|
||||
<item name="colorAccent">#6746c3</item>
|
||||
<item name="windowActionModeOverlay">true</item>
|
||||
<item name="android:datePickerDialogTheme">@style/AppCompatDialogStyle</item>
|
||||
<item name="android:colorPressedHighlight">@color/ListViewSelected</item>
|
||||
<item name="android:colorLongPressedHighlight">@color/ListViewHighlighted</item>
|
||||
<item name="android:colorFocusedHighlight">@color/ListViewSelected</item>
|
||||
<item name="android:colorActivatedHighlight">@color/ListViewSelected</item>
|
||||
<item name="android:activatedBackgroundIndicator">@color/ListViewSelected</item>
|
||||
</style>
|
||||
<style name="AppCompatDialogStyle" parent="Theme.AppCompat.Light.Dialog">
|
||||
<item name="colorAccent">#6746c3</item>
|
||||
</style>
|
||||
</resources>
|
|
@ -0,0 +1,35 @@
|
|||
using System;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using Android.Content;
|
||||
using Camelotia.Services.Interfaces;
|
||||
|
||||
namespace Camelotia.Presentation.Xamarin.Droid.Services
|
||||
{
|
||||
public sealed class AndroidAuthenticator : IAuthenticator
|
||||
{
|
||||
private readonly MainActivity _activity;
|
||||
|
||||
public AndroidAuthenticator(MainActivity activity) => _activity = activity;
|
||||
|
||||
public YandexAuthenticationType YandexAuthenticationType => YandexAuthenticationType.Token;
|
||||
|
||||
public Task<string> ReceiveYandexCode(Uri uri, IPAddress address, int port) => throw new PlatformNotSupportedException();
|
||||
|
||||
public async Task<string> ReceiveYandexToken(Uri uri)
|
||||
{
|
||||
var completion = new TaskCompletionSource<string>();
|
||||
var startWebActivity = new Intent(_activity, typeof(WebActivity));
|
||||
startWebActivity.PutExtra("url", uri.ToString());
|
||||
|
||||
_activity.StartActivityForResult(startWebActivity, 42);
|
||||
var subscription = _activity
|
||||
.AuthenticationCodeReceived
|
||||
.Subscribe(completion.SetResult);
|
||||
|
||||
var token = await completion.Task;
|
||||
subscription.Dispose();
|
||||
return token;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
using Camelotia.Services.Interfaces;
|
||||
using Plugin.FilePicker;
|
||||
using System.Threading.Tasks;
|
||||
using System.IO;
|
||||
using Android.Widget;
|
||||
using Android.Content.PM;
|
||||
using Android.OS;
|
||||
using Android;
|
||||
|
||||
namespace Camelotia.Presentation.Xamarin.Droid.Services
|
||||
{
|
||||
public sealed class AndroidFileManager : IFileManager
|
||||
{
|
||||
private readonly MainActivity _activity;
|
||||
|
||||
public AndroidFileManager(MainActivity activity) => _activity = activity;
|
||||
|
||||
public async Task<(string Name, Stream Stream)> OpenRead()
|
||||
{
|
||||
CheckAppPermissions();
|
||||
var file = await CrossFilePicker.Current.PickFile();
|
||||
if (file == null) return (null, null);
|
||||
|
||||
var fileName = file.FileName;
|
||||
var stream = file.GetStream();
|
||||
return (fileName, stream);
|
||||
}
|
||||
|
||||
public Task<Stream> OpenWrite(string name) => Task.Run(() =>
|
||||
{
|
||||
CheckAppPermissions();
|
||||
name = name.Replace(' ', '_');
|
||||
var downloads = Environment.DirectoryDownloads;
|
||||
var path = Environment.GetExternalStoragePublicDirectory(downloads).AbsolutePath;
|
||||
var filePath = Path.Combine(path, name);
|
||||
|
||||
var stream = (Stream)File.Create(filePath);
|
||||
_activity.RunOnUiThread(() =>
|
||||
{
|
||||
var toast = $"File {name} was downloaded";
|
||||
Toast.MakeText(_activity, toast, ToastLength.Long).Show();
|
||||
});
|
||||
|
||||
return stream;
|
||||
});
|
||||
|
||||
private void CheckAppPermissions()
|
||||
{
|
||||
if ((int)Build.VERSION.SdkInt < 23) return;
|
||||
|
||||
var manager = _activity.PackageManager;
|
||||
var packageName = _activity.PackageName;
|
||||
|
||||
var read = Manifest.Permission.ReadExternalStorage;
|
||||
var write = Manifest.Permission.WriteExternalStorage;
|
||||
if (manager.CheckPermission(read, packageName) != Permission.Granted &&
|
||||
manager.CheckPermission(write, packageName) != Permission.Granted)
|
||||
{
|
||||
_activity.RequestPermissions(new string[]
|
||||
{
|
||||
Manifest.Permission.ReadExternalStorage,
|
||||
Manifest.Permission.WriteExternalStorage
|
||||
}, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
using Android.App;
|
||||
using Android.Content;
|
||||
using Android.OS;
|
||||
using Android.Webkit;
|
||||
using System;
|
||||
|
||||
namespace Camelotia.Presentation.Xamarin.Droid
|
||||
{
|
||||
[Activity(Label = "Authorization")]
|
||||
public class WebActivity : Activity
|
||||
{
|
||||
protected override void OnCreate(Bundle savedInstanceState)
|
||||
{
|
||||
base.OnCreate(savedInstanceState);
|
||||
SetContentView(Resource.Layout.WebActivity);
|
||||
|
||||
var webView = (WebView)FindViewById(Resource.Id.web_activity_web_view);
|
||||
webView.RequestFocus(Android.Views.FocusSearchDirection.Down);
|
||||
webView.SetWebViewClient(new WebViewObserver(token =>
|
||||
{
|
||||
var data = new Intent();
|
||||
data.PutExtra("token", token);
|
||||
SetResult(Result.Ok, data);
|
||||
Finish();
|
||||
}));
|
||||
|
||||
var url = Intent.GetStringExtra("url");
|
||||
webView.ClearHistory();
|
||||
webView.ClearFormData();
|
||||
webView.ClearCache(true);
|
||||
|
||||
CookieManager.Instance.RemoveAllCookie();
|
||||
webView.LoadUrl(url);
|
||||
}
|
||||
|
||||
public class WebViewObserver : WebViewClient
|
||||
{
|
||||
private readonly Action<string> _tokenReceived;
|
||||
|
||||
public WebViewObserver(Action<string> tokenReceived) => _tokenReceived = tokenReceived;
|
||||
|
||||
public override void OnPageFinished(WebView view, string url)
|
||||
{
|
||||
base.OnPageFinished(view, url);
|
||||
if (!url.Contains('#')) return;
|
||||
var token = url
|
||||
.Split('#')[1]
|
||||
.Split('&')[0]
|
||||
.Split('=')[1];
|
||||
_tokenReceived(token);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<Application xmlns="http://xamarin.com/schemas/2014/forms"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
x:Class="Camelotia.Presentation.Xamarin.App">
|
||||
<Application.Resources>
|
||||
|
||||
</Application.Resources>
|
||||
</Application>
|
|
@ -0,0 +1,17 @@
|
|||
using Camelotia.Presentation.Interfaces;
|
||||
using Camelotia.Presentation.Xamarin.View;
|
||||
using Xamarin.Forms;
|
||||
using Xamarin.Forms.Xaml;
|
||||
|
||||
[assembly: XamlCompilation(XamlCompilationOptions.Compile)]
|
||||
namespace Camelotia.Presentation.Xamarin
|
||||
{
|
||||
public partial class App : Application
|
||||
{
|
||||
public App(IMainViewModel viewModel)
|
||||
{
|
||||
InitializeComponent();
|
||||
MainPage = new MainView { ViewModel = viewModel };
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ReactiveUI.XamForms" Version="9.5.1" />
|
||||
<PackageReference Include="Xamarin.Forms" Version="3.4.0.1008975" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Camelotia.Presentation\Camelotia.Presentation.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Update="View\DirectAuthView.xaml.cs">
|
||||
<DependentUpon>DirectAuthView.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Update="View\MainMasterView.xaml.cs">
|
||||
<DependentUpon>MainMasterView.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Update="View\MainProviderView.xaml.cs">
|
||||
<DependentUpon>MainProviderView.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Update="View\ProviderExplorerFileView.xaml.cs">
|
||||
<DependentUpon>ProviderExplorerFileView.xaml</DependentUpon>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Update="View\ProviderExplorerView.xaml">
|
||||
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Update="View\AuthView.xaml">
|
||||
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Update="View\DirectAuthView.xaml">
|
||||
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Update="View\MainView.xaml">
|
||||
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Update="View\OAuthView.xaml">
|
||||
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Update="View\ProviderExplorerFileView.xaml">
|
||||
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Update="View\ProviderView.xaml">
|
||||
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Update="View\MainProviderView.xaml">
|
||||
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<rxui:ReactiveTabbedPage
|
||||
x:TypeArguments="vm:IAuthViewModel"
|
||||
xmlns="http://xamarin.com/schemas/2014/forms"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
xmlns:rxui="clr-namespace:ReactiveUI.XamForms;assembly=ReactiveUI.XamForms"
|
||||
xmlns:vm="clr-namespace:Camelotia.Presentation.Interfaces;assembly=Camelotia.Presentation"
|
||||
xmlns:view="clr-namespace:Camelotia.Presentation.Xamarin.View"
|
||||
x:Class="Camelotia.Presentation.Xamarin.View.AuthView"
|
||||
Title="Authentication Required">
|
||||
</rxui:ReactiveTabbedPage>
|
|
@ -0,0 +1,35 @@
|
|||
using Camelotia.Presentation.Interfaces;
|
||||
using ReactiveUI.XamForms;
|
||||
using ReactiveUI;
|
||||
using Xamarin.Forms.Xaml;
|
||||
using System.Reactive.Linq;
|
||||
using System.Reactive.Disposables;
|
||||
using System;
|
||||
|
||||
namespace Camelotia.Presentation.Xamarin.View
|
||||
{
|
||||
[XamlCompilation(XamlCompilationOptions.Compile)]
|
||||
public partial class AuthView : ReactiveTabbedPage<IAuthViewModel>
|
||||
{
|
||||
public AuthView()
|
||||
{
|
||||
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.SupportsOAuth)
|
||||
.Where(supportsOAuth => supportsOAuth)
|
||||
.Select(supports => new OAuthView { ViewModel = ViewModel.OAuth })
|
||||
.Do(view => Children.Clear())
|
||||
.Subscribe(view => Children.Add(view))
|
||||
.DisposeWith(disposables);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<rxui:ReactiveContentPage
|
||||
x:TypeArguments="vm:IDirectAuthViewModel"
|
||||
xmlns="http://xamarin.com/schemas/2014/forms"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
x:Class="Camelotia.Presentation.Xamarin.View.DirectAuthView"
|
||||
xmlns:vm="clr-namespace:Camelotia.Presentation.Interfaces;assembly=Camelotia.Presentation"
|
||||
xmlns:rxui="clr-namespace:ReactiveUI.XamForms;assembly=ReactiveUI.XamForms"
|
||||
xmlns:view="clr-namespace:Camelotia.Presentation.Xamarin.View"
|
||||
Title="Password Authorization">
|
||||
<ContentPage.Content>
|
||||
<Frame VerticalOptions="StartAndExpand"
|
||||
HorizontalOptions="FillAndExpand"
|
||||
Margin="15">
|
||||
<StackLayout>
|
||||
<Label Text="Password Authorization" />
|
||||
<Entry x:Name="LoginEntry" />
|
||||
<Entry x:Name="PasswordEntry" IsPassword="True" />
|
||||
<Button x:Name="LoginButton" Text="Login" />
|
||||
</StackLayout>
|
||||
</Frame>
|
||||
</ContentPage.Content>
|
||||
</rxui:ReactiveContentPage>
|
|
@ -0,0 +1,26 @@
|
|||
using Camelotia.Presentation.Interfaces;
|
||||
using ReactiveUI;
|
||||
using ReactiveUI.XamForms;
|
||||
using System.Reactive.Disposables;
|
||||
using Xamarin.Forms.Xaml;
|
||||
|
||||
namespace Camelotia.Presentation.Xamarin.View
|
||||
{
|
||||
[XamlCompilation(XamlCompilationOptions.Compile)]
|
||||
public partial class DirectAuthView : ReactiveContentPage<IDirectAuthViewModel>
|
||||
{
|
||||
public DirectAuthView()
|
||||
{
|
||||
InitializeComponent();
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
this.Bind(ViewModel, x => x.Username, x => x.LoginEntry.Text)
|
||||
.DisposeWith(disposables);
|
||||
this.Bind(ViewModel, x => x.Password, x => x.PasswordEntry.Text)
|
||||
.DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, x => x.Login, x => x.LoginButton)
|
||||
.DisposeWith(disposables);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<rxui:ReactiveContentPage
|
||||
x:TypeArguments="vm:IMainViewModel"
|
||||
xmlns="http://xamarin.com/schemas/2014/forms"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
xmlns:rxui="clr-namespace:ReactiveUI.XamForms;assembly=ReactiveUI.XamForms"
|
||||
xmlns:vm="clr-namespace:Camelotia.Presentation.Interfaces;assembly=Camelotia.Presentation"
|
||||
xmlns:view="clr-namespace:Camelotia.Presentation.Xamarin.View"
|
||||
x:Class="Camelotia.Presentation.Xamarin.View.MainMasterView"
|
||||
Title="Camelotia">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Label Grid.Row="0" Text="Camelotia" FontSize="21" Margin="10" FontAttributes="Bold" TextColor="#311b92" />
|
||||
<ListView x:Name="ProvidersView" HasUnevenRows="True" Grid.Row="1">
|
||||
<ListView.ItemTemplate>
|
||||
<DataTemplate x:DataType="vm:IProviderViewModel">
|
||||
<view:MainProviderView ViewModel="{Binding}" />
|
||||
</DataTemplate>
|
||||
</ListView.ItemTemplate>
|
||||
</ListView>
|
||||
<StackLayout Grid.Row="2">
|
||||
<Button x:Name="RefreshButton" Text="Refresh" Margin="12" />
|
||||
</StackLayout>
|
||||
<ProgressBar Grid.Row="0" Grid.RowSpan="3" x:Name="LoadingBar" />
|
||||
</Grid>
|
||||
</rxui:ReactiveContentPage>
|
|
@ -0,0 +1,31 @@
|
|||
using Camelotia.Presentation.Interfaces;
|
||||
using ReactiveUI;
|
||||
using ReactiveUI.XamForms;
|
||||
using System.Reactive.Disposables;
|
||||
using Xamarin.Forms.Xaml;
|
||||
|
||||
namespace Camelotia.Presentation.Xamarin.View
|
||||
{
|
||||
[XamlCompilation(XamlCompilationOptions.Compile)]
|
||||
public partial class MainMasterView : ReactiveContentPage<IMainViewModel>
|
||||
{
|
||||
public MainMasterView()
|
||||
{
|
||||
InitializeComponent();
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
this.OneWayBind(ViewModel, x => x.IsReady, x => x.ProvidersView.IsVisible)
|
||||
.DisposeWith(disposables);
|
||||
this.OneWayBind(ViewModel, x => x.IsLoading, x => x.LoadingBar.IsVisible)
|
||||
.DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, x => x.LoadProviders, x => x.RefreshButton)
|
||||
.DisposeWith(disposables);
|
||||
|
||||
this.OneWayBind(ViewModel, x => x.Providers, x => x.ProvidersView.ItemsSource)
|
||||
.DisposeWith(disposables);
|
||||
this.Bind(ViewModel, x => x.SelectedProvider, x => x.ProvidersView.SelectedItem)
|
||||
.DisposeWith(disposables);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<rxui:ReactiveViewCell
|
||||
x:TypeArguments="vm:IProviderViewModel"
|
||||
xmlns="http://xamarin.com/schemas/2014/forms"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
x:Class="Camelotia.Presentation.Xamarin.View.MainProviderView"
|
||||
xmlns:vm="clr-namespace:Camelotia.Presentation.Interfaces;assembly=Camelotia.Presentation"
|
||||
xmlns:rxui="clr-namespace:ReactiveUI.XamForms;assembly=ReactiveUI.XamForms">
|
||||
<ViewCell.View>
|
||||
<StackLayout Margin="10">
|
||||
<Label x:Name="NameLabel" FontSize="16" FontAttributes="Bold" />
|
||||
<Label x:Name="DescriptionLabel" FontAttributes="Italic" />
|
||||
<StackLayout Orientation="Horizontal" Margin="0, 5">
|
||||
<Label Text="Size: " />
|
||||
<Label x:Name="SizeLabel" />
|
||||
</StackLayout>
|
||||
</StackLayout>
|
||||
</ViewCell.View>
|
||||
</rxui:ReactiveViewCell>
|
|
@ -0,0 +1,26 @@
|
|||
using Camelotia.Presentation.Interfaces;
|
||||
using System.Reactive.Disposables;
|
||||
using Xamarin.Forms.Xaml;
|
||||
using ReactiveUI.XamForms;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace Camelotia.Presentation.Xamarin.View
|
||||
{
|
||||
[XamlCompilation(XamlCompilationOptions.Compile)]
|
||||
public partial class MainProviderView : ReactiveViewCell<IProviderViewModel>
|
||||
{
|
||||
public MainProviderView()
|
||||
{
|
||||
InitializeComponent();
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
this.OneWayBind(ViewModel, x => x.Name, x => x.NameLabel.Text)
|
||||
.DisposeWith(disposables);
|
||||
this.OneWayBind(ViewModel, x => x.Description, x => x.DescriptionLabel.Text)
|
||||
.DisposeWith(disposables);
|
||||
this.OneWayBind(ViewModel, x => x.Size, x => x.SizeLabel.Text)
|
||||
.DisposeWith(disposables);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<rxui:ReactiveMasterDetailPage
|
||||
x:TypeArguments="vm:IMainViewModel"
|
||||
xmlns="http://xamarin.com/schemas/2014/forms"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
x:Class="Camelotia.Presentation.Xamarin.View.MainView"
|
||||
xmlns:rxui="clr-namespace:ReactiveUI.XamForms;assembly=ReactiveUI.XamForms"
|
||||
xmlns:vm="clr-namespace:Camelotia.Presentation.Interfaces;assembly=Camelotia.Presentation"
|
||||
xmlns:views="clr-namespace:Camelotia.Presentation.Xamarin.View">
|
||||
<MasterDetailPage.Master>
|
||||
<views:MainMasterView ViewModel="{Binding}" />
|
||||
</MasterDetailPage.Master>
|
||||
<MasterDetailPage.Detail>
|
||||
<NavigationPage x:Name="NavigationView" />
|
||||
</MasterDetailPage.Detail>
|
||||
</rxui:ReactiveMasterDetailPage>
|
|
@ -0,0 +1,32 @@
|
|||
using Camelotia.Presentation.Interfaces;
|
||||
using Xamarin.Forms.Xaml;
|
||||
using ReactiveUI.XamForms;
|
||||
using ReactiveUI;
|
||||
using System.Reactive.Disposables;
|
||||
using System.Reactive.Linq;
|
||||
using System;
|
||||
|
||||
namespace Camelotia.Presentation.Xamarin.View
|
||||
{
|
||||
[XamlCompilation(XamlCompilationOptions.Compile)]
|
||||
public partial class MainView : ReactiveMasterDetailPage<IMainViewModel>
|
||||
{
|
||||
public MainView()
|
||||
{
|
||||
InitializeComponent();
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
this.WhenAnyValue(x => x.ViewModel.SelectedProvider)
|
||||
.Select(provider => false)
|
||||
.Subscribe(x => IsPresented = x)
|
||||
.DisposeWith(disposables);
|
||||
|
||||
this.WhenAnyValue(x => x.ViewModel.SelectedProvider)
|
||||
.Where(provider => provider != null)
|
||||
.Select(x => new ProviderView { ViewModel = ViewModel.SelectedProvider })
|
||||
.Subscribe(view => NavigationView.PushAsync(view))
|
||||
.DisposeWith(disposables);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<rxui:ReactiveContentPage
|
||||
x:TypeArguments="vm:IOAuthViewModel"
|
||||
xmlns="http://xamarin.com/schemas/2014/forms"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
x:Class="Camelotia.Presentation.Xamarin.View.OAuthView"
|
||||
xmlns:vm="clr-namespace:Camelotia.Presentation.Interfaces;assembly=Camelotia.Presentation"
|
||||
xmlns:rxui="clr-namespace:ReactiveUI.XamForms;assembly=ReactiveUI.XamForms"
|
||||
xmlns:view="clr-namespace:Camelotia.Presentation.Xamarin.View"
|
||||
Title="OAuth Authorization">
|
||||
<ContentPage.Content>
|
||||
<Frame VerticalOptions="StartAndExpand"
|
||||
HorizontalOptions="FillAndExpand"
|
||||
Margin="15">
|
||||
<StackLayout>
|
||||
<Label Text="OAuth Authorization" />
|
||||
<Button x:Name="LoginButton" Text="Authorize" />
|
||||
</StackLayout>
|
||||
</Frame>
|
||||
</ContentPage.Content>
|
||||
</rxui:ReactiveContentPage>
|
|
@ -0,0 +1,22 @@
|
|||
using Camelotia.Presentation.Interfaces;
|
||||
using System.Reactive.Disposables;
|
||||
using Xamarin.Forms.Xaml;
|
||||
using ReactiveUI.XamForms;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace Camelotia.Presentation.Xamarin.View
|
||||
{
|
||||
[XamlCompilation(XamlCompilationOptions.Compile)]
|
||||
public partial class OAuthView : ReactiveContentPage<IOAuthViewModel>
|
||||
{
|
||||
public OAuthView()
|
||||
{
|
||||
InitializeComponent();
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
this.BindCommand(ViewModel, x => x.Login, x => x.LoginButton)
|
||||
.DisposeWith(disposables);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<rxui:ReactiveViewCell
|
||||
x:TypeArguments="vm:FileModel"
|
||||
xmlns="http://xamarin.com/schemas/2014/forms"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
x:Class="Camelotia.Presentation.Xamarin.View.ProviderExplorerFileView"
|
||||
xmlns:vm="clr-namespace:Camelotia.Services.Models;assembly=Camelotia.Services"
|
||||
xmlns:rxui="clr-namespace:ReactiveUI.XamForms;assembly=ReactiveUI.XamForms">
|
||||
<ViewCell.View>
|
||||
<StackLayout Margin="8" Grid.Column="0">
|
||||
<Label x:Name="NameLabel" FontSize="16" />
|
||||
<Label x:Name="SizeLabel" FontAttributes="Bold"/>
|
||||
</StackLayout>
|
||||
</ViewCell.View>
|
||||
</rxui:ReactiveViewCell>
|
|
@ -0,0 +1,24 @@
|
|||
using Camelotia.Services.Models;
|
||||
using ReactiveUI;
|
||||
using ReactiveUI.XamForms;
|
||||
using System.Reactive.Disposables;
|
||||
using Xamarin.Forms.Xaml;
|
||||
|
||||
namespace Camelotia.Presentation.Xamarin.View
|
||||
{
|
||||
[XamlCompilation(XamlCompilationOptions.Compile)]
|
||||
public partial class ProviderExplorerFileView : ReactiveViewCell<FileModel>
|
||||
{
|
||||
public ProviderExplorerFileView()
|
||||
{
|
||||
InitializeComponent();
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
this.OneWayBind(ViewModel, x => x.Name, x => x.NameLabel.Text)
|
||||
.DisposeWith(disposables);
|
||||
this.OneWayBind(ViewModel, x => x.Size, x => x.SizeLabel.Text)
|
||||
.DisposeWith(disposables);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<rxui:ReactiveContentPage
|
||||
x:TypeArguments="vm:IProviderViewModel"
|
||||
xmlns="http://xamarin.com/schemas/2014/forms"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
x:Class="Camelotia.Presentation.Xamarin.View.ProviderExplorerView"
|
||||
xmlns:vm="clr-namespace:Camelotia.Presentation.Interfaces;assembly=Camelotia.Presentation"
|
||||
xmlns:rxui="clr-namespace:ReactiveUI.XamForms;assembly=ReactiveUI.XamForms"
|
||||
xmlns:view="clr-namespace:Camelotia.Presentation.Xamarin.View">
|
||||
<ContentPage.Content>
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid Grid.Row="0" Margin="3">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Button Grid.Column="0"
|
||||
x:Name="BackButton"
|
||||
Text="Back" />
|
||||
<Label Grid.Column="1"
|
||||
x:Name="PathLabel"
|
||||
HorizontalTextAlignment="Center"
|
||||
VerticalTextAlignment="Center"
|
||||
FontSize="14"
|
||||
Margin="15, 0" />
|
||||
<Button Grid.Column="2"
|
||||
x:Name="OpenButton"
|
||||
Text="Open" />
|
||||
<Button Grid.Column="3"
|
||||
x:Name="RefreshButton"
|
||||
Text="Refresh" />
|
||||
</Grid>
|
||||
<ListView Grid.Row="1"
|
||||
x:Name="FilesListView"
|
||||
HasUnevenRows="True">
|
||||
<ListView.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<view:ProviderExplorerFileView ViewModel="{Binding}" />
|
||||
</DataTemplate>
|
||||
</ListView.ItemTemplate>
|
||||
</ListView>
|
||||
<Grid Grid.Row="2">
|
||||
<StackLayout Orientation="Horizontal"
|
||||
HorizontalOptions="StartAndExpand"
|
||||
Margin="10, 5">
|
||||
<Label Text="You selected: " />
|
||||
<Label x:Name="SelectedFileNameLabel" TextColor="Accent" />
|
||||
</StackLayout>
|
||||
</Grid>
|
||||
<Grid Grid.Row="3" Margin="3">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Button Grid.Column="0"
|
||||
x:Name="LogoutButton"
|
||||
Text="Logout" />
|
||||
<Button Grid.Column="1"
|
||||
x:Name="DeleteButton"
|
||||
Text="Delete" />
|
||||
<Button Grid.Column="3"
|
||||
x:Name="UploadButton"
|
||||
Text="Upload" />
|
||||
<Button Grid.Column="4"
|
||||
x:Name="DownloadButton"
|
||||
Text="Download" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</ContentPage.Content>
|
||||
</rxui:ReactiveContentPage>
|
|
@ -0,0 +1,56 @@
|
|||
using Camelotia.Presentation.Interfaces;
|
||||
using System.Reactive.Disposables;
|
||||
using Xamarin.Forms.Xaml;
|
||||
using ReactiveUI.XamForms;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace Camelotia.Presentation.Xamarin.View
|
||||
{
|
||||
[XamlCompilation(XamlCompilationOptions.Compile)]
|
||||
public partial class ProviderExplorerView : ReactiveContentPage<IProviderViewModel>
|
||||
{
|
||||
public ProviderExplorerView()
|
||||
{
|
||||
InitializeComponent();
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
this.BindCommand(ViewModel, x => x.Back, x => x.BackButton)
|
||||
.DisposeWith(disposables);
|
||||
this.OneWayBind(ViewModel, x => x.CurrentPath, x => x.PathLabel.Text)
|
||||
.DisposeWith(disposables);
|
||||
|
||||
this.BindCommand(ViewModel, x => x.Refresh, x => x.RefreshButton)
|
||||
.DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, x => x.Open, x => x.OpenButton)
|
||||
.DisposeWith(disposables);
|
||||
|
||||
this.OneWayBind(ViewModel, x => x.Files, x => x.FilesListView.ItemsSource)
|
||||
.DisposeWith(disposables);
|
||||
this.Bind(ViewModel, x => x.SelectedFile, x => x.FilesListView.SelectedItem)
|
||||
.DisposeWith(disposables);
|
||||
|
||||
this.OneWayBind(ViewModel, x => x.IsLoading, x => x.FilesListView.IsRefreshing)
|
||||
.DisposeWith(disposables);
|
||||
this.OneWayBind(ViewModel, x => x.Refresh, x => x.FilesListView.RefreshCommand)
|
||||
.DisposeWith(disposables);
|
||||
|
||||
this.OneWayBind(ViewModel, x => x.CanLogout, x => x.LogoutButton.IsVisible)
|
||||
.DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, x => x.Logout, x => x.LogoutButton)
|
||||
.DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, x => x.DeleteSelectedFile, x => x.DeleteButton)
|
||||
.DisposeWith(disposables);
|
||||
|
||||
this.OneWayBind(ViewModel, x => x.SelectedFile.Name, x => x.SelectedFileNameLabel.Text)
|
||||
.DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, x => x.UploadToCurrentPath, x => x.UploadButton)
|
||||
.DisposeWith(disposables);
|
||||
this.BindCommand(ViewModel, x => x.DownloadSelectedFile, x => x.DownloadButton)
|
||||
.DisposeWith(disposables);
|
||||
|
||||
this.OneWayBind(ViewModel, x => x.Name, x => x.Title)
|
||||
.DisposeWith(disposables);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<rxui:ReactiveNavigationPage
|
||||
x:TypeArguments="vm:IProviderViewModel"
|
||||
xmlns="http://xamarin.com/schemas/2014/forms"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
x:Class="Camelotia.Presentation.Xamarin.View.ProviderView"
|
||||
xmlns:vm="clr-namespace:Camelotia.Presentation.Interfaces;assembly=Camelotia.Presentation"
|
||||
xmlns:rxui="clr-namespace:ReactiveUI.XamForms;assembly=ReactiveUI.XamForms"
|
||||
xmlns:view="clr-namespace:Camelotia.Presentation.Xamarin.View">
|
||||
</rxui:ReactiveNavigationPage>
|
|
@ -0,0 +1,46 @@
|
|||
using Camelotia.Presentation.Interfaces;
|
||||
using Xamarin.Forms.Xaml;
|
||||
using ReactiveUI.XamForms;
|
||||
using ReactiveUI;
|
||||
using System.Reactive.Linq;
|
||||
using System.Reactive.Disposables;
|
||||
using System;
|
||||
using Xamarin.Forms;
|
||||
using System.Linq;
|
||||
|
||||
namespace Camelotia.Presentation.Xamarin.View
|
||||
{
|
||||
[XamlCompilation(XamlCompilationOptions.Compile)]
|
||||
public partial class ProviderView : ReactiveNavigationPage<IProviderViewModel>
|
||||
{
|
||||
public ProviderView()
|
||||
{
|
||||
InitializeComponent();
|
||||
SetHasNavigationBar(this, false);
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
this.WhenAnyValue(x => x.ViewModel.Auth.IsAuthenticated)
|
||||
.Where(authenticated => authenticated)
|
||||
.DistinctUntilChanged()
|
||||
.Select(x => new ProviderExplorerView { ViewModel = ViewModel })
|
||||
.Subscribe(NavigateWithoutBackStack)
|
||||
.DisposeWith(disposables);
|
||||
|
||||
this.WhenAnyValue(x => x.ViewModel.Auth.IsAuthenticated)
|
||||
.Where(authenticated => !authenticated)
|
||||
.DistinctUntilChanged()
|
||||
.Select(x => new AuthView { ViewModel = ViewModel.Auth })
|
||||
.Subscribe(NavigateWithoutBackStack)
|
||||
.DisposeWith(disposables);
|
||||
});
|
||||
}
|
||||
|
||||
private async void NavigateWithoutBackStack(Page page)
|
||||
{
|
||||
if (Navigation.NavigationStack.Any())
|
||||
Navigation.InsertPageBefore(page, Navigation.NavigationStack.First());
|
||||
else await Navigation.PushAsync(page);
|
||||
await Navigation.PopToRootAsync();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -9,10 +9,9 @@
|
|||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ReactiveUI" Version="9.1.1" />
|
||||
<PackageReference Include="ReactiveUI.Fody" Version="9.1.1" />
|
||||
<PackageReference Include="DynamicData" Version="6.6.1.2507" />
|
||||
<PackageReference Include="Refit" Version="4.6.48" />
|
||||
<PackageReference Include="ReactiveUI" Version="9.5.1" />
|
||||
<PackageReference Include="ReactiveUI.Fody" Version="9.5.1" />
|
||||
<PackageReference Include="DynamicData" Version="6.7.1.2534" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="akavache" Version="6.0.31" />
|
||||
<PackageReference Include="System.Reactive" Version="4.0.0" />
|
||||
<PackageReference Include="akavache" Version="6.2.3" />
|
||||
<PackageReference Include="System.Reactive" Version="4.1.2" />
|
||||
<PackageReference Include="VkNet" Version="1.40.0" />
|
||||
</ItemGroup>
|
||||
|
||||
|
|
|
@ -13,6 +13,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Camelotia.Presentation.Test
|
|||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Camelotia.Presentation.Uwp", "Camelotia.Presentation.Uwp\Camelotia.Presentation.Uwp.csproj", "{359DA275-5214-457A-887D-DDBD9763667B}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Camelotia.Presentation.Xamarin.Droid", "Camelotia.Presentation.Xamarin.Android\Camelotia.Presentation.Xamarin.Droid.csproj", "{24CE3C36-16B9-426D-AA0C-5961ECF8D88C}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Camelotia.Presentation.Xamarin", "Camelotia.Presentation.Xamarin\Camelotia.Presentation.Xamarin.csproj", "{F019715C-675A-463B-AF36-58585F6FA7DF}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
@ -133,6 +137,56 @@ Global
|
|||
{359DA275-5214-457A-887D-DDBD9763667B}.Release|x86.ActiveCfg = Release|x86
|
||||
{359DA275-5214-457A-887D-DDBD9763667B}.Release|x86.Build.0 = Release|x86
|
||||
{359DA275-5214-457A-887D-DDBD9763667B}.Release|x86.Deploy.0 = Release|x86
|
||||
{24CE3C36-16B9-426D-AA0C-5961ECF8D88C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{24CE3C36-16B9-426D-AA0C-5961ECF8D88C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{24CE3C36-16B9-426D-AA0C-5961ECF8D88C}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
|
||||
{24CE3C36-16B9-426D-AA0C-5961ECF8D88C}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||
{24CE3C36-16B9-426D-AA0C-5961ECF8D88C}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||
{24CE3C36-16B9-426D-AA0C-5961ECF8D88C}.Debug|ARM.Deploy.0 = Debug|Any CPU
|
||||
{24CE3C36-16B9-426D-AA0C-5961ECF8D88C}.Debug|ARM64.ActiveCfg = Debug|Any CPU
|
||||
{24CE3C36-16B9-426D-AA0C-5961ECF8D88C}.Debug|ARM64.Build.0 = Debug|Any CPU
|
||||
{24CE3C36-16B9-426D-AA0C-5961ECF8D88C}.Debug|ARM64.Deploy.0 = Debug|Any CPU
|
||||
{24CE3C36-16B9-426D-AA0C-5961ECF8D88C}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{24CE3C36-16B9-426D-AA0C-5961ECF8D88C}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{24CE3C36-16B9-426D-AA0C-5961ECF8D88C}.Debug|x64.Deploy.0 = Debug|Any CPU
|
||||
{24CE3C36-16B9-426D-AA0C-5961ECF8D88C}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{24CE3C36-16B9-426D-AA0C-5961ECF8D88C}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{24CE3C36-16B9-426D-AA0C-5961ECF8D88C}.Debug|x86.Deploy.0 = Debug|Any CPU
|
||||
{24CE3C36-16B9-426D-AA0C-5961ECF8D88C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{24CE3C36-16B9-426D-AA0C-5961ECF8D88C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{24CE3C36-16B9-426D-AA0C-5961ECF8D88C}.Release|Any CPU.Deploy.0 = Release|Any CPU
|
||||
{24CE3C36-16B9-426D-AA0C-5961ECF8D88C}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||
{24CE3C36-16B9-426D-AA0C-5961ECF8D88C}.Release|ARM.Build.0 = Release|Any CPU
|
||||
{24CE3C36-16B9-426D-AA0C-5961ECF8D88C}.Release|ARM.Deploy.0 = Release|Any CPU
|
||||
{24CE3C36-16B9-426D-AA0C-5961ECF8D88C}.Release|ARM64.ActiveCfg = Release|Any CPU
|
||||
{24CE3C36-16B9-426D-AA0C-5961ECF8D88C}.Release|ARM64.Build.0 = Release|Any CPU
|
||||
{24CE3C36-16B9-426D-AA0C-5961ECF8D88C}.Release|ARM64.Deploy.0 = Release|Any CPU
|
||||
{24CE3C36-16B9-426D-AA0C-5961ECF8D88C}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{24CE3C36-16B9-426D-AA0C-5961ECF8D88C}.Release|x64.Build.0 = Release|Any CPU
|
||||
{24CE3C36-16B9-426D-AA0C-5961ECF8D88C}.Release|x64.Deploy.0 = Release|Any CPU
|
||||
{24CE3C36-16B9-426D-AA0C-5961ECF8D88C}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{24CE3C36-16B9-426D-AA0C-5961ECF8D88C}.Release|x86.Build.0 = Release|Any CPU
|
||||
{24CE3C36-16B9-426D-AA0C-5961ECF8D88C}.Release|x86.Deploy.0 = Release|Any CPU
|
||||
{F019715C-675A-463B-AF36-58585F6FA7DF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{F019715C-675A-463B-AF36-58585F6FA7DF}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{F019715C-675A-463B-AF36-58585F6FA7DF}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||
{F019715C-675A-463B-AF36-58585F6FA7DF}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||
{F019715C-675A-463B-AF36-58585F6FA7DF}.Debug|ARM64.ActiveCfg = Debug|Any CPU
|
||||
{F019715C-675A-463B-AF36-58585F6FA7DF}.Debug|ARM64.Build.0 = Debug|Any CPU
|
||||
{F019715C-675A-463B-AF36-58585F6FA7DF}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{F019715C-675A-463B-AF36-58585F6FA7DF}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{F019715C-675A-463B-AF36-58585F6FA7DF}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{F019715C-675A-463B-AF36-58585F6FA7DF}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{F019715C-675A-463B-AF36-58585F6FA7DF}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{F019715C-675A-463B-AF36-58585F6FA7DF}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{F019715C-675A-463B-AF36-58585F6FA7DF}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||
{F019715C-675A-463B-AF36-58585F6FA7DF}.Release|ARM.Build.0 = Release|Any CPU
|
||||
{F019715C-675A-463B-AF36-58585F6FA7DF}.Release|ARM64.ActiveCfg = Release|Any CPU
|
||||
{F019715C-675A-463B-AF36-58585F6FA7DF}.Release|ARM64.Build.0 = Release|Any CPU
|
||||
{F019715C-675A-463B-AF36-58585F6FA7DF}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{F019715C-675A-463B-AF36-58585F6FA7DF}.Release|x64.Build.0 = Release|Any CPU
|
||||
{F019715C-675A-463B-AF36-58585F6FA7DF}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{F019715C-675A-463B-AF36-58585F6FA7DF}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
20
README.md
|
@ -6,7 +6,7 @@ The app runs on Windows, Linux, MacOS, XBox, Surface Hub and HoloLens.
|
|||
|
||||
You can compile .NET Standard libraries, run tests and run an Avalonia application on Windows, Linux and macOS operating systems. Make sure you have latest [.NET Core SDK](https://dot.net/) installed.
|
||||
|
||||
<img src="./Camelotia.png" width="500">
|
||||
<img src="./UiAvalonia.png" width="500">
|
||||
|
||||
```sh
|
||||
# Linux or MacOS shell
|
||||
|
@ -21,7 +21,13 @@ On Windows, double-click the `./run.bat` file.
|
|||
|
||||
You can compile Universal Windows Platform Camelotia app only on latest Windows 10. Make sure you have latest [Microsoft Visual Studio](https://visualstudio.microsoft.com/) installed. Make sure the "Universal Application Development" section is checked in [Visual Studio Installer](https://visualstudio.microsoft.com/ru/vs/).
|
||||
|
||||
<img src="./Universal.jpg" width="500">
|
||||
<img src="./UiWindows.jpg" width="500">
|
||||
|
||||
## Compiling Xamarin Forms app
|
||||
|
||||
To compile the Xamarin Forms Android application, you need to install appropriate Android SDK v8.1. This can be achieved by using [Visual Studio Installer](https://visualstudio.microsoft.com/ru/vs/) and selecting "Mobile Development" section there.
|
||||
|
||||
<img src="./UiAndroid1.png" width="220"> <img src="./UiAndroid2.png" width="220">
|
||||
|
||||
### Adding Custom Providers
|
||||
|
||||
|
@ -29,8 +35,10 @@ File system providers are located at `./Camelotia.Services/Providers/`. To add a
|
|||
|
||||
### Technologies and Tools Used
|
||||
|
||||
- <a href="https://reactiveui.net/">ReactiveUI</a>
|
||||
- <a href="http://github.com/avaloniaui">AvaloniaUI</a>
|
||||
- <a href="https://github.com/nsubstitute/NSubstitute">NSubstitute</a>
|
||||
- <a href="https://github.com/fluentassertions/fluentassertions">FluentAssertions</a>
|
||||
- <a href="https://reactiveui.net/">ReactiveUI</a> modern MVVM framework
|
||||
- <a href="http://github.com/avaloniaui">AvaloniaUI</a> cross-platform GUI framework
|
||||
- <a href="https://github.com/nsubstitute/NSubstitute">NSubstitute</a> mocking library
|
||||
- <a href="https://github.com/fluentassertions/fluentassertions">FluentAssertions</a> assertions library
|
||||
- <a href="https://docs.microsoft.com/en-us/xamarin/xamarin-forms/">Xamarin.Forms</a> mobile GUI framework
|
||||
- <a href="https://docs.microsoft.com/en-us/windows/uwp/get-started/universal-application-platform-guide">Universal Windows Platform</a>
|
||||
- <a href="https://www.jetbrains.com/rider/">JetBrains Rider IDE</a>
|
||||
|
|
После Ширина: | Высота: | Размер: 120 KiB |
После Ширина: | Высота: | Размер: 140 KiB |
До Ширина: | Высота: | Размер: 72 KiB После Ширина: | Высота: | Размер: 72 KiB |
До Ширина: | Высота: | Размер: 124 KiB После Ширина: | Высота: | Размер: 124 KiB |
|
@ -5,7 +5,7 @@ jobs:
|
|||
variables:
|
||||
buildConfiguration: 'Release'
|
||||
steps:
|
||||
- script: dotnet build --configuration $(buildConfiguration)
|
||||
- script: dotnet build --configuration $(buildConfiguration) $(Build.SourcesDirectory)/Camelotia.Presentation.Avalonia/Camelotia.Presentation.Avalonia.csproj
|
||||
displayName: 'Linux Build'
|
||||
- script: dotnet test --logger trx Camelotia.Presentation.Tests
|
||||
displayName: 'Linux Unit Tests'
|
||||
|
@ -20,7 +20,7 @@ jobs:
|
|||
variables:
|
||||
buildConfiguration: 'Release'
|
||||
steps:
|
||||
- script: dotnet build --configuration $(buildConfiguration)
|
||||
- script: dotnet build --configuration $(buildConfiguration) $(Build.SourcesDirectory)/Camelotia.Presentation.Avalonia/Camelotia.Presentation.Avalonia.csproj
|
||||
displayName: 'Windows Build'
|
||||
- script: |
|
||||
mkdir $(Build.SourcesDirectory)\results
|
||||
|
|