Skip to content

Commit

Permalink
Restore ReactiveUI.Validation.AndroidX (#693)
Browse files Browse the repository at this point in the history
  • Loading branch information
ChrisPulman authored Sep 20, 2024
1 parent 4503c3c commit 8884b6f
Show file tree
Hide file tree
Showing 3 changed files with 206 additions and 1 deletion.
181 changes: 181 additions & 0 deletions src/ReactiveUI.Validation.AndroidX/Extensions/ViewForExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
// Copyright (c) 2024 .NET Foundation and Contributors. All rights reserved.
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for full license information.

using System;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Linq.Expressions;
using Google.Android.Material.TextField;
using ReactiveUI.Validation.Abstractions;
using ReactiveUI.Validation.Formatters;
using ReactiveUI.Validation.Formatters.Abstractions;
using ReactiveUI.Validation.Helpers;
using ReactiveUI.Validation.ValidationBindings;
using Splat;

// ReSharper disable once CheckNamespace
namespace ReactiveUI.Validation.Extensions;

/// <summary>
/// Android specific extensions methods associated to <see cref="IViewFor"/> instances.
/// </summary>
[SuppressMessage("Roslynator", "RCS1163", Justification = "Needed for Expression context.")]
public static class ViewForExtensions
{
/// <summary>
/// Platform binding to the TextInputLayout.
/// </summary>
/// <typeparam name="TView">IViewFor of TViewModel.</typeparam>
/// <typeparam name="TViewModel">ViewModel type.</typeparam>
/// <typeparam name="TViewModelProperty">ViewModel property type.</typeparam>
/// <param name="view">IViewFor instance.</param>
/// <param name="viewModel">ViewModel instance. Can be null, used for generic type resolution.</param>
/// <param name="viewModelProperty">ViewModel property.</param>
/// <param name="viewProperty">View property to bind the validation message.</param>
/// <param name="formatter">
/// Validation formatter. Defaults to <see cref="SingleLineFormatter"/>. In order to override the global
/// default value, implement <see cref="IValidationTextFormatter{TOut}"/> and register an instance of
/// IValidationTextFormatter&lt;string&gt; into Splat.Locator.
/// </param>
/// <returns>Returns a <see cref="IDisposable"/> object.</returns>
[SuppressMessage("Design", "CA1801: Parameter unused", Justification = "Used for generic resolution.")]
public static IDisposable BindValidation<TView, TViewModel, TViewModelProperty>(
this TView view,
TViewModel? viewModel,
Expression<Func<TViewModel, TViewModelProperty?>> viewModelProperty,
TextInputLayout viewProperty,
IValidationTextFormatter<string>? formatter = null)
where TView : IViewFor<TViewModel>
where TViewModel : class, IReactiveObject, IValidatableViewModel
{
if (view is null)
{
throw new ArgumentNullException(nameof(view));
}

if (viewModelProperty is null)
{
throw new ArgumentNullException(nameof(viewModelProperty));
}

if (viewProperty is null)
{
throw new ArgumentNullException(nameof(viewProperty));
}

formatter ??= Locator.Current.GetService<IValidationTextFormatter<string>>() ??
SingleLineFormatter.Default;

return ValidationBinding.ForProperty(
view,
viewModelProperty,
(_, errors) => viewProperty.Error = errors.FirstOrDefault(msg => !string.IsNullOrEmpty(msg)),
formatter);
}

/// <summary>
/// Platform binding to the TextInputLayout.
/// </summary>
/// <remarks>Supports multiple validations for the same property.</remarks>
/// <typeparam name="TView">IViewFor of TViewModel.</typeparam>
/// <typeparam name="TViewModel">ViewModel type.</typeparam>
/// <typeparam name="TViewModelProperty">ViewModel property type.</typeparam>
/// <param name="view">IViewFor instance.</param>
/// <param name="viewModel">ViewModel instance. Can be null, used for generic type resolution.</param>
/// <param name="viewModelProperty">ViewModel property.</param>
/// <param name="viewProperty">View property to bind the validation message.</param>
/// <param name="formatter">
/// Validation formatter. Defaults to <see cref="SingleLineFormatter"/>. In order to override the global
/// default value, implement <see cref="IValidationTextFormatter{TOut}"/> and register an instance of
/// IValidationTextFormatter&lt;string&gt; into Splat.Locator.
/// </param>
/// <returns>Returns a <see cref="IDisposable"/> object.</returns>
[ExcludeFromCodeCoverage]
[Obsolete("This method is no longer required, BindValidation now supports multiple validations.")]
[SuppressMessage("Design", "CA1801: Parameter unused", Justification = "Used for generic resolution.")]
public static IDisposable BindValidationEx<TView, TViewModel, TViewModelProperty>(
this TView view,
TViewModel? viewModel,
Expression<Func<TViewModel, TViewModelProperty?>> viewModelProperty,
TextInputLayout viewProperty,
IValidationTextFormatter<string>? formatter = null)
where TView : IViewFor<TViewModel>
where TViewModel : class, IReactiveObject, IValidatableViewModel
{
if (view is null)
{
throw new ArgumentNullException(nameof(view));
}

if (viewModelProperty is null)
{
throw new ArgumentNullException(nameof(viewModelProperty));
}

if (viewProperty is null)
{
throw new ArgumentNullException(nameof(viewProperty));
}

formatter ??= Locator.Current.GetService<IValidationTextFormatter<string>>() ??
SingleLineFormatter.Default;

return ValidationBinding.ForProperty(
view,
viewModelProperty,
(_, errors) => viewProperty.Error = errors.FirstOrDefault(msg => !string.IsNullOrEmpty(msg)),
formatter);
}

/// <summary>
/// Platform binding to the TextInputLayout.
/// </summary>
/// <typeparam name="TView">IViewFor of TViewModel.</typeparam>
/// <typeparam name="TViewModel">ViewModel type.</typeparam>
/// <param name="view">IViewFor instance.</param>
/// <param name="viewModel">ViewModel instance. Can be null, used for generic type resolution.</param>
/// <param name="viewModelHelperProperty">ViewModel's ValidationHelper property.</param>
/// <param name="viewProperty">View property to bind the validation message.</param>
/// <param name="formatter">
/// Validation formatter. Defaults to <see cref="SingleLineFormatter"/>. In order to override the global
/// default value, implement <see cref="IValidationTextFormatter{TOut}"/> and register an instance of
/// IValidationTextFormatter&lt;string&gt; into Splat.Locator.
/// </param>
/// <returns>Returns a <see cref="IDisposable"/> object.</returns>
[SuppressMessage("Design", "CA1801: Parameter unused", Justification = "Used for generic resolution.")]
public static IDisposable BindValidation<TView, TViewModel>(
this TView view,
TViewModel? viewModel,
Expression<Func<TViewModel?, ValidationHelper?>> viewModelHelperProperty,
TextInputLayout viewProperty,
IValidationTextFormatter<string>? formatter = null)
where TView : IViewFor<TViewModel>
where TViewModel : class, IReactiveObject, IValidatableViewModel
{
if (view is null)
{
throw new ArgumentNullException(nameof(view));
}

if (viewModelHelperProperty is null)
{
throw new ArgumentNullException(nameof(viewModelHelperProperty));
}

if (viewProperty is null)
{
throw new ArgumentNullException(nameof(viewProperty));
}

formatter ??= Locator.Current.GetService<IValidationTextFormatter<string>>() ??
SingleLineFormatter.Default;

return ValidationBinding.ForValidationHelperProperty(
view,
viewModelHelperProperty,
(_, errorText) => viewProperty.Error = errorText,
formatter);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net8.0-android</TargetFrameworks>
<PackageDescription>Provides ReactiveUI.Validation extensions for the AndroidX Library</PackageDescription>
<PackageId>ReactiveUI.Validation.AndroidX</PackageId>
<NoWarn>$(NoWarn);CS1591</NoWarn>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="ReactiveUI.AndroidX" Version="20.*" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\ReactiveUI.Validation\ReactiveUI.Validation.csproj" />
</ItemGroup>
</Project>
8 changes: 7 additions & 1 deletion src/ReactiveUI.Validation.sln
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
# 17
VisualStudioVersion = 17.9.34728.123
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReactiveUI.Validation", "ReactiveUI.Validation\ReactiveUI.Validation.csproj", "{B62AABD0-22A4-470D-B6EB-F6B3EAE668DE}"
Expand All @@ -18,6 +18,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
..\version.json = ..\version.json
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReactiveUI.Validation.AndroidX", "ReactiveUI.Validation.AndroidX\ReactiveUI.Validation.AndroidX.csproj", "{6E984244-95F9-4EA6-BEE2-F665C0C4BCFD}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -32,6 +34,10 @@ Global
{892D51D9-7A3F-4E66-A871-082A63D9BE05}.Debug|Any CPU.Build.0 = Debug|Any CPU
{892D51D9-7A3F-4E66-A871-082A63D9BE05}.Release|Any CPU.ActiveCfg = Release|Any CPU
{892D51D9-7A3F-4E66-A871-082A63D9BE05}.Release|Any CPU.Build.0 = Release|Any CPU
{6E984244-95F9-4EA6-BEE2-F665C0C4BCFD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6E984244-95F9-4EA6-BEE2-F665C0C4BCFD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6E984244-95F9-4EA6-BEE2-F665C0C4BCFD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6E984244-95F9-4EA6-BEE2-F665C0C4BCFD}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down

0 comments on commit 8884b6f

Please sign in to comment.